package handlers

import (
	"errors"
	"net/http"
	"testing"
)

func TestMapPlaylistError(t *testing.T) {
	tests := []struct {
		name           string
		err            error
		expectedMsg    string
		expectedStatus int
	}{
		{
			name:           "nil error",
			err:            nil,
			expectedMsg:    "Une erreur inconnue s'est produite",
			expectedStatus: http.StatusInternalServerError,
		},
		{
			name:           "validation error - title",
			err:            errors.New("invalid title"),
			expectedMsg:    "Le titre de la playlist est requis et doit contenir entre 1 et 200 caractères",
			expectedStatus: http.StatusBadRequest,
		},
		{
			name:           "validation error - description",
			err:            errors.New("invalid description"),
			expectedMsg:    "La description ne peut pas dépasser 1000 caractères",
			expectedStatus: http.StatusBadRequest,
		},
		{
			name:           "forbidden error",
			err:            errors.New("forbidden"),
			expectedMsg:    "Vous n'avez pas la permission d'effectuer cette action sur cette playlist",
			expectedStatus: http.StatusForbidden,
		},
		{
			name:           "unauthorized error",
			err:            errors.New("unauthorized"),
			expectedMsg:    "Vous devez être connecté pour effectuer cette action",
			expectedStatus: http.StatusUnauthorized,
		},
		{
			name:           "not found - playlist",
			err:            errors.New("playlist not found"),
			expectedMsg:    "Cette playlist n'existe pas ou a été supprimée",
			expectedStatus: http.StatusNotFound,
		},
		{
			name:           "not found - track",
			err:            errors.New("track not found"),
			expectedMsg:    "Ce morceau n'existe pas ou n'est pas accessible",
			expectedStatus: http.StatusNotFound,
		},
		{
			name:           "network error",
			err:            errors.New("network timeout"),
			expectedMsg:    "Une erreur réseau s'est produite. Veuillez réessayer dans quelques instants",
			expectedStatus: http.StatusServiceUnavailable,
		},
		{
			name:           "database error",
			err:            errors.New("database query failed"),
			expectedMsg:    "Une erreur de base de données s'est produite. Veuillez réessayer plus tard",
			expectedStatus: http.StatusInternalServerError,
		},
		{
			name:           "quota error",
			err:            errors.New("quota exceeded"),
			expectedMsg:    "Vous avez atteint la limite autorisée. Veuillez supprimer certaines ressources pour continuer",
			expectedStatus: http.StatusForbidden,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			msg, status := mapPlaylistError(tt.err)
			if msg != tt.expectedMsg {
				t.Errorf("mapPlaylistError() message = %v, want %v", msg, tt.expectedMsg)
			}
			if status != tt.expectedStatus {
				t.Errorf("mapPlaylistError() status = %v, want %v", status, tt.expectedStatus)
			}
		})
	}
}

func TestIsRetryableError(t *testing.T) {
	tests := []struct {
		name     string
		err      error
		expected bool
	}{
		{
			name:     "nil error",
			err:      nil,
			expected: false,
		},
		{
			name:     "not found error - not retryable",
			err:      errors.New("playlist not found"),
			expected: false,
		},
		{
			name:     "forbidden error - not retryable",
			err:      errors.New("forbidden"),
			expected: false,
		},
		{
			name:     "unauthorized error - not retryable",
			err:      errors.New("unauthorized"),
			expected: false,
		},
		{
			name:     "validation error - not retryable",
			err:      errors.New("invalid title"),
			expected: false,
		},
		{
			name:     "network error - retryable",
			err:      errors.New("network timeout"),
			expected: true,
		},
		{
			name:     "database error - retryable",
			err:      errors.New("database connection failed"),
			expected: true,
		},
		{
			name:     "connection error - retryable",
			err:      errors.New("connection refused"),
			expected: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := isRetryableError(tt.err)
			if result != tt.expected {
				t.Errorf("isRetryableError() = %v, want %v", result, tt.expected)
			}
		})
	}
}

func TestGetPlaylistErrorStatusCode(t *testing.T) {
	tests := []struct {
		name     string
		err      error
		expected int
	}{
		{
			name:     "validation error",
			err:      errors.New("invalid title"),
			expected: http.StatusBadRequest,
		},
		{
			name:     "forbidden error",
			err:      errors.New("forbidden"),
			expected: http.StatusForbidden,
		},
		{
			name:     "not found error",
			err:      errors.New("playlist not found"),
			expected: http.StatusNotFound,
		},
		{
			name:     "network error",
			err:      errors.New("network timeout"),
			expected: http.StatusServiceUnavailable,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := getPlaylistErrorStatusCode(tt.err)
			if result != tt.expected {
				t.Errorf("getPlaylistErrorStatusCode() = %v, want %v", result, tt.expected)
			}
		})
	}
}

func TestGetPlaylistErrorMessage(t *testing.T) {
	tests := []struct {
		name     string
		err      error
		expected string
	}{
		{
			name:     "validation error",
			err:      errors.New("invalid title"),
			expected: "Le titre de la playlist est requis et doit contenir entre 1 et 200 caractères",
		},
		{
			name:     "forbidden error",
			err:      errors.New("forbidden"),
			expected: "Vous n'avez pas la permission d'effectuer cette action sur cette playlist",
		},
		{
			name:     "not found error",
			err:      errors.New("playlist not found"),
			expected: "Cette playlist n'existe pas ou a été supprimée",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := getPlaylistErrorMessage(tt.err)
			if result != tt.expected {
				t.Errorf("getPlaylistErrorMessage() = %v, want %v", result, tt.expected)
			}
		})
	}
}
