package handler

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

	"github.com/gofiber/fiber/v2"
	"github.com/stretchr/testify/assert"
)

func TestHandleKratosCourierRelay_Email(t *testing.T) {
	redis := &mockRedisRepo{data: make(map[string]string)}
	emailSvc := &mockEmailService{}

	h := &AuthHandler{
		RedisService: redis,
		EmailService: emailSvc,
	}
	app := fiber.New()
	app.Post("/api/v1/auth/kratos/courier", h.HandleKratosCourierRelay)

	// Simulate Kratos Courier Request for Email
	reqBody := map[string]any{
		"recipient":     "user@example.com",
		"template_type": "verification_code",
		"template_data": map[string]any{
			"verification_code": "123456",
		},
		"subject": "Verify your email",
		"body":    "Your code is 123456",
	}
	body, _ := json.Marshal(reqBody)
	req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/kratos/courier", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")

	resp, _ := app.Test(req, -1)
	assert.Equal(t, http.StatusOK, resp.StatusCode)
}

func TestVerifySignupCode_Success(t *testing.T) {
	redis := &mockRedisRepo{data: make(map[string]string)}
	h := &AuthHandler{
		RedisService: redis,
	}
	app := fiber.New()
	app.Post("/api/v1/auth/signup/verify", h.VerifySignupCode)

	// Mock stored code in redis
	// signup:email:user@test.com -> {"code":"654321", "verified":false, "expires_at":...}
	state := map[string]any{
		"code":       "654321",
		"verified":   false,
		"expires_at": 9999999999, // far future
	}
	stateJSON, _ := json.Marshal(state)
	redis.data["signup:email:user@test.com"] = string(stateJSON)

	// Verify Code
	verifyBody := map[string]string{
		"type":   "email",
		"target": "user@test.com",
		"code":   "654321",
	}
	body, _ := json.Marshal(verifyBody)
	req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/signup/verify", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")

	resp, _ := app.Test(req, -1)
	assert.Equal(t, http.StatusOK, resp.StatusCode)

	var res map[string]any
	json.NewDecoder(resp.Body).Decode(&res)
	assert.True(t, res["success"].(bool))

	// Check redis state updated to verified
	val, _ := redis.Get("signup:email:user@test.com")
	var updatedState map[string]any
	json.Unmarshal([]byte(val), &updatedState)
	assert.True(t, updatedState["verified"].(bool))
}

func TestVerifySignupCode_Invalid(t *testing.T) {
	redis := &mockRedisRepo{data: make(map[string]string)}
	h := &AuthHandler{
		RedisService: redis,
	}
	app := fiber.New()
	app.Post("/api/v1/auth/signup/verify", h.VerifySignupCode)

	stateJSON, _ := json.Marshal(map[string]any{
		"code":       "111111",
		"expires_at": 9999999999,
	})
	redis.data["signup:email:user@test.com"] = string(stateJSON)

	verifyBody := map[string]string{
		"type":   "email",
		"target": "user@test.com",
		"code":   "222222", // wrong code
	}
	body, _ := json.Marshal(verifyBody)
	req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/signup/verify", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")

	resp, _ := app.Test(req, -1)
	assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
}
