package handlers

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

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

// MockCSRFMiddleware mocks CSRFMiddleware
type MockCSRFMiddleware struct {
	mock.Mock
}

func (m *MockCSRFMiddleware) GetToken(ctx context.Context, userID uuid.UUID) (string, error) {
	args := m.Called(ctx, userID)
	return args.String(0), args.Error(1)
}

func setupTestCSRFRouter(mockCSRFMiddleware *MockCSRFMiddleware) *gin.Engine {
	gin.SetMode(gin.TestMode)
	router := gin.New()

	logger := zap.NewNop()
	handler := NewCSRFHandlerWithInterface(mockCSRFMiddleware, logger)

	api := router.Group("/api/v1")
	api.Use(func(c *gin.Context) {
		userIDStr := c.GetHeader("X-User-ID")
		if userIDStr != "" {
			uid, err := uuid.Parse(userIDStr)
			if err == nil {
				c.Set("user_id", uid)
			}
		}
		c.Next()
	})
	{
		api.GET("/csrf-token", handler.GetCSRFToken())
	}

	return router
}

func TestCSRFHandler_GetCSRFToken_Success(t *testing.T) {
	// Setup
	mockCSRFMiddleware := new(MockCSRFMiddleware)
	router := setupTestCSRFRouter(mockCSRFMiddleware)

	userID := uuid.New()
	expectedToken := "test-csrf-token"

	mockCSRFMiddleware.On("GetToken", mock.Anything, userID).Return(expectedToken, nil)

	// Execute
	req, _ := http.NewRequest("GET", "/api/v1/csrf-token", nil)
	req.Header.Set("X-User-ID", userID.String())
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	// Assert
	assert.Equal(t, http.StatusOK, w.Code)
	var response map[string]interface{}
	err := json.Unmarshal(w.Body.Bytes(), &response)
	assert.NoError(t, err)
	assert.True(t, response["success"].(bool))
	data := response["data"].(map[string]interface{})
	assert.Equal(t, expectedToken, data["csrf_token"])
	mockCSRFMiddleware.AssertExpectations(t)
}

func TestCSRFHandler_GetCSRFToken_Unauthorized(t *testing.T) {
	// Setup
	mockCSRFMiddleware := new(MockCSRFMiddleware)
	router := setupTestCSRFRouter(mockCSRFMiddleware)

	// Execute - No X-User-ID header
	req, _ := http.NewRequest("GET", "/api/v1/csrf-token", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	// Assert
	assert.Equal(t, http.StatusUnauthorized, w.Code)
	mockCSRFMiddleware.AssertNotCalled(t, "GetToken")
}

func TestCSRFHandler_GetCSRFToken_ServiceError(t *testing.T) {
	// Setup
	mockCSRFMiddleware := new(MockCSRFMiddleware)
	router := setupTestCSRFRouter(mockCSRFMiddleware)

	userID := uuid.New()

	mockCSRFMiddleware.On("GetToken", mock.Anything, userID).Return("", assert.AnError)

	// Execute
	req, _ := http.NewRequest("GET", "/api/v1/csrf-token", nil)
	req.Header.Set("X-User-ID", userID.String())
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	// Assert
	assert.Equal(t, http.StatusInternalServerError, w.Code)
	mockCSRFMiddleware.AssertExpectations(t)
}
