package handler_test

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

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

func setupSMSHandler() (*handler.SMSHandler, *gin.Engine) {
	gin.SetMode(gin.TestMode)

	l1Cache := cache.NewL1Cache()
	l2Cache := cache.NewRedisCache(false)
	cacheManager := cache.NewCacheManager(l1Cache, l2Cache)

	// Create mock SMS provider
	mockProvider := &service.MockSMSProvider{}
	smsConfig := service.DefaultSMSCodeConfig()
	smsCodeSvc := service.NewSMSCodeService(mockProvider, cacheManager, smsConfig)

	// Create handler with nil authService (for SendCode tests)
	h := handler.NewSMSHandler(nil, smsCodeSvc)

	router := gin.New()
	router.POST("/api/v1/sms/send", h.SendCode)

	return h, router
}

func TestSMSHandler_SendCode(t *testing.T) {
	_, router := setupSMSHandler()

	tests := []struct {
		name       string
		body       map[string]interface{}
		wantStatus int
		wantCode   float64
	}{
		{
			name:       "valid phone",
			body:       map[string]interface{}{"phone": "13800138000", "purpose": "login"},
			wantStatus: http.StatusOK,
			wantCode:   0,
		},
		{
			name:       "invalid phone",
			body:       map[string]interface{}{"phone": "invalid", "purpose": "login"},
			wantStatus: http.StatusBadRequest, // Handler returns 400 for invalid phone
			wantCode:   400,
		},
		{
			name:       "missing phone",
			body:       map[string]interface{}{"purpose": "login"},
			wantStatus: http.StatusBadRequest,
			wantCode:   400,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			body, _ := json.Marshal(tt.body)
			w := httptest.NewRecorder()
			req, _ := http.NewRequest("POST", "/api/v1/sms/send", bytes.NewBuffer(body))
			req.Header.Set("Content-Type", "application/json")
			router.ServeHTTP(w, req)

			assert.Equal(t, tt.wantStatus, w.Code)

			var resp map[string]interface{}
			if err := json.Unmarshal(w.Body.Bytes(), &resp); err == nil {
				if tt.wantCode == 0 {
					assert.Equal(t, float64(0), resp["code"])
				}
			}
		})
	}
}

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

	// Handler with nil smsCodeService
	h := handler.NewSMSHandler(nil, nil)

	router := gin.New()
	router.POST("/api/v1/sms/send", h.SendCode)

	body, _ := json.Marshal(map[string]interface{}{"phone": "13800138000", "purpose": "login"})
	w := httptest.NewRecorder()
	req, _ := http.NewRequest("POST", "/api/v1/sms/send", bytes.NewBuffer(body))
	req.Header.Set("Content-Type", "application/json")
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusServiceUnavailable, w.Code)

	var resp map[string]interface{}
	json.Unmarshal(w.Body.Bytes(), &resp)
	assert.Equal(t, float64(503), resp["code"])
}
