package httpapi

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

	"github.com/easyai/easyai-ai-gateway/apps/api/internal/clients"
	"github.com/easyai/easyai-ai-gateway/apps/api/internal/store"
)

func TestRateLimitErrorDetailIncludesUserGroupAndExceededMetric(t *testing.T) {
	resetAt := time.Date(2026, 5, 15, 10, 30, 0, 0, time.UTC)
	detail := rateLimitErrorDetail(&store.RateLimitExceededError{
		ScopeType:     "user_group",
		ScopeKey:      "group-1",
		ScopeName:     "VIP 用户组",
		ScopeMetadata: map[string]any{"groupKey": "vip"},
		Metric:        "rpm",
		Limit:         2,
		Amount:        1,
		Current:       2,
		Used:          1,
		Reserved:      1,
		Projected:     3,
		WindowSeconds: 60,
		ResetAt:       resetAt,
		RetryAfter:    5 * time.Second,
		Retryable:     true,
		Policy: map[string]any{
			"rules": []any{
				map[string]any{"metric": "rpm", "limit": float64(2), "windowSeconds": float64(60)},
			},
		},
	})
	if detail["metric"] != "rpm" || detail["projected"] != float64(3) || detail["limit"] != float64(2) {
		t.Fatalf("unexpected exceeded detail: %+v", detail)
	}
	userGroup, _ := detail["userGroup"].(map[string]any)
	if userGroup["id"] != "group-1" || userGroup["groupKey"] != "vip" || userGroup["name"] != "VIP 用户组" {
		t.Fatalf("missing user group detail: %+v", detail)
	}
	matchedRule, _ := detail["matchedRule"].(map[string]any)
	if matchedRule["metric"] != "rpm" {
		t.Fatalf("missing matched rule: %+v", detail)
	}
	if detail["retryAfterMs"] != int64(5000) || detail["resetAt"] != resetAt.Format(time.RFC3339Nano) {
		t.Fatalf("missing retry/reset detail: %+v", detail)
	}
}

func TestQueueFullAndTimeoutPublicContracts(t *testing.T) {
	queueErr := &store.RateLimitExceededError{
		ScopeType:  "platform_model",
		ScopeKey:   "model-1",
		Metric:     "queue_size",
		Reason:     "queue_full",
		Limit:      2,
		Current:    2,
		Projected:  3,
		QueueDepth: 2,
		QueueLimit: 2,
		RetryAfter: 1500 * time.Millisecond,
		Retryable:  true,
	}
	recorder := httptest.NewRecorder()
	applyRunErrorHeaders(recorder, queueErr)
	if statusFromRunError(queueErr) != http.StatusTooManyRequests || runErrorCode(queueErr) != "gateway_rate_limited" {
		t.Fatalf("queue full contract status=%d code=%s", statusFromRunError(queueErr), runErrorCode(queueErr))
	}
	if recorder.Header().Get("Retry-After") != "2" {
		t.Fatalf("Retry-After = %q, want 2", recorder.Header().Get("Retry-After"))
	}
	details := runErrorDetails(queueErr)
	detail, _ := details["rateLimit"].(map[string]any)
	if detail["reason"] != "queue_full" || detail["queueDepth"] != 2 || detail["queueLimit"] != 2 {
		t.Fatalf("queue full details = %+v", details)
	}

	timeoutErr := &store.QueueTimeoutError{TaskID: "task-1"}
	if statusFromRunError(timeoutErr) != http.StatusGatewayTimeout || runErrorCode(timeoutErr) != "queue_timeout" {
		t.Fatalf("queue timeout contract status=%d code=%s", statusFromRunError(timeoutErr), runErrorCode(timeoutErr))
	}
}

func TestStatusFromRunErrorPreservesUpstreamHTTPStatus(t *testing.T) {
	for _, status := range []int{http.StatusBadRequest, http.StatusNotFound, http.StatusMethodNotAllowed, http.StatusConflict, http.StatusRequestEntityTooLarge, http.StatusUnsupportedMediaType, http.StatusUnprocessableEntity, http.StatusTooManyRequests} {
		err := &clients.ClientError{Code: fmt.Sprintf("http_%d", status), Message: "raw upstream error", StatusCode: status}
		if got := statusFromRunError(err); got != status {
			t.Fatalf("statusFromRunError(%d) = %d", status, got)
		}
	}
}

func TestRunErrorMessageIncludesRateLimitSummary(t *testing.T) {
	message := runErrorMessage(&store.RateLimitExceededError{
		ScopeType:     "user_group",
		ScopeKey:      "group-1",
		ScopeName:     "VIP 用户组",
		ScopeMetadata: map[string]any{"groupKey": "vip"},
		Metric:        "rpm",
		Limit:         2,
		Amount:        1,
		Current:       2,
		Projected:     3,
		WindowSeconds: 60,
		RetryAfter:    5 * time.Second,
		Retryable:     true,
		Message:       "rate limit exceeded: rpm window has no remaining capacity",
	})
	for _, expected := range []string{"限流摘要", "用户组 VIP 用户组(vip)", "rpm 超限", "当前 2", "本次 1", "预计 3", "限制 2", "窗口 60 秒", "约5秒后可重试"} {
		if !strings.Contains(message, expected) {
			t.Fatalf("message %q should contain %q", message, expected)
		}
	}
}
