package api

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/zap"
)

func TestNewVersionManager(t *testing.T) {
	logger, _ := zap.NewDevelopment()
	vm := NewVersionManager(logger)

	assert.NotNil(t, vm)
	assert.Equal(t, DefaultAPIVersion, vm.GetDefaultVersion())
	assert.NotEmpty(t, vm.GetAllVersions())
}

func TestVersionManager_RegisterVersion(t *testing.T) {
	logger, _ := zap.NewDevelopment()
	vm := NewVersionManager(logger)

	version := &APIVersion{
		Version:     "v2",
		Deprecated:  false,
		Description: "New API version",
	}

	vm.RegisterVersion(version)

	retrieved, exists := vm.GetVersion("v2")
	require.True(t, exists)
	assert.Equal(t, version, retrieved)
}

func TestVersionManager_GetVersion_NotFound(t *testing.T) {
	logger, _ := zap.NewDevelopment()
	vm := NewVersionManager(logger)

	_, exists := vm.GetVersion("v99")
	assert.False(t, exists)
}

func TestNormalizeVersion(t *testing.T) {
	tests := []struct {
		input    string
		expected string
	}{
		{"v1", "v1"},
		{"1", "v1"},
		{"V1", "v1"},
		{" v2 ", "v2"},
		{"2", "v2"},
	}

	for _, tt := range tests {
		t.Run(tt.input, func(t *testing.T) {
			result := normalizeVersion(tt.input)
			assert.Equal(t, tt.expected, result)
		})
	}
}

func TestParseAcceptHeader(t *testing.T) {
	tests := []struct {
		name     string
		accept   string
		expected string
	}{
		{
			name:     "vnd.veza.v1",
			accept:   "application/vnd.veza.v1+json",
			expected: "v1",
		},
		{
			name:     "vnd.veza.v2",
			accept:   "application/vnd.veza.v2+json",
			expected: "v2",
		},
		{
			name:     "multiple accept types",
			accept:   "application/json, application/vnd.veza.v1+json",
			expected: "v1",
		},
		{
			name:     "no version",
			accept:   "application/json",
			expected: "",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := parseAcceptHeader(tt.accept)
			assert.Equal(t, tt.expected, result)
		})
	}
}

func TestVersionMiddleware_HeaderXAPIVersion(t *testing.T) {
	gin.SetMode(gin.TestMode)
	logger, _ := zap.NewDevelopment()
	vm := NewVersionManager(logger)

	router := gin.New()
	router.Use(VersionMiddleware(vm))
	router.GET("/test", func(c *gin.Context) {
		version := GetAPIVersion(c)
		c.JSON(200, gin.H{"version": version})
	})

	w := httptest.NewRecorder()
	req := httptest.NewRequest("GET", "/test", nil)
	req.Header.Set(APIVersionHeader, "v1")
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
	assert.Equal(t, "v1", w.Header().Get(APIVersionHeader))
}

func TestVersionMiddleware_AcceptHeader(t *testing.T) {
	gin.SetMode(gin.TestMode)
	logger, _ := zap.NewDevelopment()
	vm := NewVersionManager(logger)

	router := gin.New()
	router.Use(VersionMiddleware(vm))
	router.GET("/test", func(c *gin.Context) {
		version := GetAPIVersion(c)
		c.JSON(200, gin.H{"version": version})
	})

	w := httptest.NewRecorder()
	req := httptest.NewRequest("GET", "/test", nil)
	req.Header.Set(AcceptHeaderVersion, "application/vnd.veza.v1+json")
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
}

func TestVersionMiddleware_InvalidVersion(t *testing.T) {
	gin.SetMode(gin.TestMode)
	logger, _ := zap.NewDevelopment()
	vm := NewVersionManager(logger)

	router := gin.New()
	router.Use(VersionMiddleware(vm))
	router.GET("/test", func(c *gin.Context) {
		c.JSON(200, gin.H{"ok": true})
	})

	w := httptest.NewRecorder()
	req := httptest.NewRequest("GET", "/test", nil)
	req.Header.Set(APIVersionHeader, "v99")
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestVersionMiddleware_DeprecatedVersion(t *testing.T) {
	gin.SetMode(gin.TestMode)
	logger, _ := zap.NewDevelopment()
	vm := NewVersionManager(logger)

	// Enregistrer une version dépréciée
	vm.RegisterVersion(&APIVersion{
		Version:     "v0",
		Deprecated:  true,
		SunsetDate:  "2025-12-31T00:00:00Z",
		Description: "Deprecated version",
	})

	router := gin.New()
	router.Use(VersionMiddleware(vm))
	router.GET("/test", func(c *gin.Context) {
		c.JSON(200, gin.H{"ok": true})
	})

	w := httptest.NewRecorder()
	req := httptest.NewRequest("GET", "/test", nil)
	req.Header.Set(APIVersionHeader, "v0")
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
	assert.Equal(t, "true", w.Header().Get("X-API-Deprecated"))
	assert.Equal(t, "true", w.Header().Get("X-API-Version-Deprecated"))
	assert.Equal(t, "2025-12-31T00:00:00Z", w.Header().Get("Sunset"))
}

func TestVersionInfoHandler(t *testing.T) {
	gin.SetMode(gin.TestMode)
	logger, _ := zap.NewDevelopment()
	vm := NewVersionManager(logger)

	router := gin.New()
	router.GET("/api/versions", VersionInfoHandler(vm))

	w := httptest.NewRecorder()
	req := httptest.NewRequest("GET", "/api/versions", nil)
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
	assert.Contains(t, w.Body.String(), "current_version")
	assert.Contains(t, w.Body.String(), "versions")
}
