package handler_test

import (
	"bytes"
	"encoding/json"
	"io"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gin-gonic/gin"
	"github.com/user-management-system/internal/api/handler"
	"github.com/user-management-system/internal/cache"
	"github.com/user-management-system/internal/service"
)

// =============================================================================
// Captcha Handler Tests - TDD approach
// =============================================================================

func TestCaptchaHandler_GenerateCaptcha(t *testing.T) {
	gin.SetMode(gin.TestMode)

	l1Cache := cache.NewL1Cache()
	l2Cache := cache.NewRedisCache(false)
	cacheManager := cache.NewCacheManager(l1Cache, l2Cache)
	captchaSvc := service.NewCaptchaService(cacheManager)
	h := handler.NewCaptchaHandler(captchaSvc)

	t.Run("生成验证码成功", func(t *testing.T) {
		w := httptest.NewRecorder()
		c, _ := gin.CreateTestContext(w)
		c.Request = httptest.NewRequest("GET", "/api/v1/captcha/generate", nil)

		h.GenerateCaptcha(c)

		if w.Code != http.StatusOK {
			t.Errorf("期望状态码 %d, 得到 %d", http.StatusOK, w.Code)
		}

		var resp map[string]interface{}
		if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
			t.Fatalf("解析响应失败: %v", err)
		}

		if resp["code"].(float64) != 0 {
			t.Errorf("期望 code=0, 得到 %v", resp["code"])
		}

		data := resp["data"].(map[string]interface{})
		if data["captcha_id"] == "" {
			t.Error("captcha_id 不应为空")
		}
		if data["image"] == "" {
			t.Error("image 不应为空")
		}
	})
}

func TestCaptchaHandler_VerifyCaptcha(t *testing.T) {
	gin.SetMode(gin.TestMode)

	l1Cache := cache.NewL1Cache()
	l2Cache := cache.NewRedisCache(false)
	cacheManager := cache.NewCacheManager(l1Cache, l2Cache)
	captchaSvc := service.NewCaptchaService(cacheManager)
	h := handler.NewCaptchaHandler(captchaSvc)

	t.Run("验证成功", func(t *testing.T) {
		// 先生成验证码
		result, _ := captchaSvc.Generate(nil)
		// 从缓存获取答案
		cachedVal, ok := cacheManager.Get(nil, "captcha:"+result.CaptchaID)
		if !ok {
			t.Fatal("验证码未存储到缓存")
		}
		answer := cachedVal.(string)

		w := httptest.NewRecorder()
		c, _ := gin.CreateTestContext(w)
		body := `{"captcha_id":"` + result.CaptchaID + `","answer":"` + answer + `"}`
		c.Request = httptest.NewRequest("POST", "/api/v1/captcha/verify", nil)
		c.Request.Body = io.NopCloser(bytes.NewReader([]byte(body)))
		c.Request.Header.Set("Content-Type", "application/json")

		h.VerifyCaptcha(c)

		if w.Code != http.StatusOK {
			t.Errorf("期望状态码 %d, 得到 %d", http.StatusOK, w.Code)
		}
	})

	t.Run("验证失败-错误答案", func(t *testing.T) {
		result, _ := captchaSvc.Generate(nil)

		w := httptest.NewRecorder()
		c, _ := gin.CreateTestContext(w)
		body := `{"captcha_id":"` + result.CaptchaID + `","answer":"wrong"}`
		c.Request = httptest.NewRequest("POST", "/api/v1/captcha/verify", nil)
		c.Request.Body = io.NopCloser(bytes.NewReader([]byte(body)))
		c.Request.Header.Set("Content-Type", "application/json")

		h.VerifyCaptcha(c)

		if w.Code != http.StatusBadRequest {
			t.Errorf("期望状态码 %d, 得到 %d", http.StatusBadRequest, w.Code)
		}
	})

	t.Run("验证失败-缺少参数", func(t *testing.T) {
		w := httptest.NewRecorder()
		c, _ := gin.CreateTestContext(w)
		body := `{"captcha_id":""}`
		c.Request = httptest.NewRequest("POST", "/api/v1/captcha/verify", nil)
		c.Request.Body = io.NopCloser(bytes.NewReader([]byte(body)))
		c.Request.Header.Set("Content-Type", "application/json")

		h.VerifyCaptcha(c)

		if w.Code != http.StatusBadRequest {
			t.Errorf("期望状态码 %d, 得到 %d", http.StatusBadRequest, w.Code)
		}
	})
}

func TestCaptchaHandler_GetCaptchaImage(t *testing.T) {
	gin.SetMode(gin.TestMode)

	l1Cache := cache.NewL1Cache()
	l2Cache := cache.NewRedisCache(false)
	cacheManager := cache.NewCacheManager(l1Cache, l2Cache)
	captchaSvc := service.NewCaptchaService(cacheManager)
	h := handler.NewCaptchaHandler(captchaSvc)

	t.Run("获取验证码图片", func(t *testing.T) {
		w := httptest.NewRecorder()
		c, _ := gin.CreateTestContext(w)
		c.Request = httptest.NewRequest("GET", "/api/v1/captcha/image?captcha_id=test", nil)

		h.GetCaptchaImage(c)

		if w.Code != http.StatusOK {
			t.Errorf("期望状态码 %d, 得到 %d", http.StatusOK, w.Code)
		}
	})
}
