package auth

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

	"github.com/gin-gonic/gin"
	"hyapp-admin-server/internal/config"
	authcore "hyapp-admin-server/internal/service"
)

func TestRefreshUsesRootCookieAndClearsLegacyCookiePath(t *testing.T) {
	gin.SetMode(gin.TestMode)
	store := newFakeAuthStore(t)
	handler := testAuthHandler(store)
	login, err := handler.service.Login(LoginInput{Username: "admin", Password: "secret", IP: "127.0.0.1", UserAgent: "browser"})
	if err != nil {
		t.Fatalf("login: %v", err)
	}
	router := gin.New()
	router.POST("/api/v1/auth/refresh", handler.Refresh)

	req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/refresh", nil)
	req.AddCookie(&http.Cookie{Name: refreshCookieName, Value: login.RefreshToken})
	rec := httptest.NewRecorder()
	router.ServeHTTP(rec, req)

	if rec.Code != http.StatusOK {
		t.Fatalf("refresh status = %d body=%s", rec.Code, rec.Body.String())
	}
	setCookies := rec.Result().Cookies()
	if !hasCookieWithPath(setCookies, refreshCookieName, refreshCookiePath) {
		t.Fatalf("refresh must set root refresh cookie: %+v", setCookies)
	}
	if !hasExpiredCookieWithPath(setCookies, refreshCookieName, legacyRefreshCookiePath) {
		t.Fatalf("refresh must clear legacy path cookie: %+v", setCookies)
	}
}

func TestRefreshTriesDuplicateRefreshCookiesUntilOneWorks(t *testing.T) {
	gin.SetMode(gin.TestMode)
	store := newFakeAuthStore(t)
	handler := testAuthHandler(store)
	first, err := handler.service.Login(LoginInput{Username: "admin", Password: "secret", IP: "127.0.0.1", UserAgent: "browser"})
	if err != nil {
		t.Fatalf("login: %v", err)
	}
	refreshed, err := handler.service.Refresh(first.RefreshToken, LoginInput{IP: "127.0.0.1", UserAgent: "browser"})
	if err != nil {
		t.Fatalf("prime refresh: %v", err)
	}
	router := gin.New()
	router.POST("/api/v1/auth/refresh", handler.Refresh)

	req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/refresh", nil)
	req.Header.Set("Cookie", refreshCookieName+"="+first.RefreshToken+"; "+refreshCookieName+"="+refreshed.RefreshToken)
	rec := httptest.NewRecorder()
	router.ServeHTTP(rec, req)

	if rec.Code != http.StatusOK {
		t.Fatalf("refresh status = %d body=%s", rec.Code, rec.Body.String())
	}
	if strings.Contains(rec.Body.String(), "刷新会话已失效") {
		t.Fatalf("refresh should skip stale duplicate cookie: %s", rec.Body.String())
	}
}

func testAuthHandler(store *fakeAuthStore) *Handler {
	cfg := config.Config{RefreshTokenTTL: 7 * 24 * time.Hour, RefreshCookieSameSite: "lax"}
	return &Handler{
		service: NewService(store, authcore.NewAuthService("test-secret", time.Hour), cfg),
		cfg:     cfg,
	}
}

func hasCookieWithPath(cookies []*http.Cookie, name string, path string) bool {
	for _, cookie := range cookies {
		if cookie.Name == name && cookie.Path == path && cookie.MaxAge >= 0 && cookie.Value != "" {
			return true
		}
	}
	return false
}

func hasExpiredCookieWithPath(cookies []*http.Cookie, name string, path string) bool {
	for _, cookie := range cookies {
		if cookie.Name == name && cookie.Path == path && cookie.MaxAge < 0 {
			return true
		}
	}
	return false
}
