package httpx

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/require"
	"senlinai-agent/backend/internal/config"
)

func TestHealthz(t *testing.T) {
	router := NewRouter(config.Config{Env: "test"})
	req := httptest.NewRequest(http.MethodGet, "/healthz", nil)
	rec := httptest.NewRecorder()

	router.ServeHTTP(rec, req)

	require.Equal(t, http.StatusOK, rec.Code)
	require.JSONEq(t, `{"status":"ok"}`, rec.Body.String())
}

func TestNewRouterRegistersFeatureRoutesUnderAPI(t *testing.T) {
	router := NewRouter(config.Config{Env: "test"}, testRegistrar{})
	req := httptest.NewRequest(http.MethodGet, "/api/ping", nil)
	rec := httptest.NewRecorder()

	router.ServeHTTP(rec, req)

	require.Equal(t, http.StatusOK, rec.Code)
	require.JSONEq(t, `{"pong":true}`, rec.Body.String())
}

func TestAPIStatusReturnsChangingTimestampMillisecondsWithoutAuth(t *testing.T) {
	router := NewProtectedRouter(config.Config{Env: "test"}, func(token string) (uint, error) {
		return 0, http.ErrNoCookie
	})

	first := getStatusTimestamp(t, router)
	time.Sleep(2 * time.Millisecond)
	second := getStatusTimestamp(t, router)

	require.Greater(t, first, int64(0))
	require.Greater(t, second, first)
}

func TestRouterAddsCORSHeadersForLocalWebClient(t *testing.T) {
	router := NewRouter(config.Config{Env: "test"}, testRegistrar{})
	req := httptest.NewRequest(http.MethodGet, "/api/ping", nil)
	req.Header.Set("Origin", "http://localhost:5173")
	rec := httptest.NewRecorder()

	router.ServeHTTP(rec, req)

	require.Equal(t, http.StatusOK, rec.Code)
	require.Equal(t, "http://localhost:5173", rec.Header().Get("Access-Control-Allow-Origin"))
	require.Contains(t, rec.Header().Get("Access-Control-Allow-Headers"), "Authorization")
}

func TestRouterHandlesCORSPreflightBeforeAuth(t *testing.T) {
	router := NewProtectedRouter(config.Config{Env: "test"}, func(token string) (uint, error) {
		return 0, http.ErrNoCookie
	}, testRegistrar{})
	req := httptest.NewRequest(http.MethodOptions, "/api/ping", nil)
	req.Header.Set("Origin", "http://localhost:5173")
	req.Header.Set("Access-Control-Request-Method", "GET")
	req.Header.Set("Access-Control-Request-Headers", "Authorization")
	rec := httptest.NewRecorder()

	router.ServeHTTP(rec, req)

	require.Equal(t, http.StatusNoContent, rec.Code)
	require.Equal(t, "http://localhost:5173", rec.Header().Get("Access-Control-Allow-Origin"))
	require.Contains(t, rec.Header().Get("Access-Control-Allow-Headers"), "Authorization")
}

type testRegistrar struct{}

func (testRegistrar) Register(router gin.IRouter) {
	router.GET("/ping", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"pong": true})
	})
}

func getStatusTimestamp(t *testing.T, router http.Handler) int64 {
	t.Helper()
	req := httptest.NewRequest(http.MethodGet, "/api/status", nil)
	rec := httptest.NewRecorder()

	router.ServeHTTP(rec, req)

	require.Equal(t, http.StatusOK, rec.Code)
	var payload struct {
		TimestampMS int64 `json:"timestamp_ms"`
	}
	require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &payload))
	return payload.TimestampMS
}
