package http

import (
	"crypto/ed25519"
	"crypto/rand"
	"encoding/base64"
	"encoding/json"
	"io"
	"log/slog"
	stdhttp "net/http"
	"net/http/httptest"
	"testing"
	"time"

	"qycw/go-server/internal/bootstrap"
	"qycw/go-server/internal/config"
	licenseclient "qycw/go-server/internal/license"
	"qycw/go-server/internal/settings"
)

func TestRouterMatchesMigratedAPIRoutes(t *testing.T) {
	licenseEval := testLicenseEvaluator(t)
	router := NewRouter(&bootstrap.App{
		Config: config.Bootstrap{
			AppName:                  "test",
			AppVersion:               "test",
			JWTSecretKey:             "test-secret",
			AccessTokenExpireMinutes: 30,
			RefreshTokenExpireDays:   7,
		},
		Settings:    settings.NewMemoryStore(),
		LicenseEval: licenseEval,
	}, slog.New(slog.NewTextHandler(io.Discard, nil)))

	tests := []struct {
		name       string
		method     string
		path       string
		wantStatus int
	}{
		{name: "store categories", method: stdhttp.MethodGet, path: "/api/v1/store/categories", wantStatus: stdhttp.StatusServiceUnavailable},
		{name: "public activities", method: stdhttp.MethodGet, path: "/api/v1/activities", wantStatus: stdhttp.StatusServiceUnavailable},
		{name: "public activity detail", method: stdhttp.MethodGet, path: "/api/v1/activities/1", wantStatus: stdhttp.StatusServiceUnavailable},
		{name: "cart list", method: stdhttp.MethodGet, path: "/api/v1/cart", wantStatus: stdhttp.StatusUnauthorized},
		{name: "cart add", method: stdhttp.MethodPost, path: "/api/v1/cart", wantStatus: stdhttp.StatusUnauthorized},
		{name: "orders list", method: stdhttp.MethodGet, path: "/api/v1/orders", wantStatus: stdhttp.StatusUnauthorized},
		{name: "service orders", method: stdhttp.MethodGet, path: "/api/v1/orders/service-orders", wantStatus: stdhttp.StatusUnauthorized},
		{name: "unsubscribe order", method: stdhttp.MethodPost, path: "/api/v1/orders/123/unsubscribe", wantStatus: stdhttp.StatusUnauthorized},
		{name: "order detail", method: stdhttp.MethodGet, path: "/api/v1/orders/123", wantStatus: stdhttp.StatusUnauthorized},
		{name: "order preview", method: stdhttp.MethodPost, path: "/api/v1/orders/preview", wantStatus: stdhttp.StatusUnauthorized},
		{name: "checkout", method: stdhttp.MethodPost, path: "/api/v1/orders/checkout", wantStatus: stdhttp.StatusUnauthorized},
		{name: "coupon preview", method: stdhttp.MethodPost, path: "/api/v1/orders/coupons/preview", wantStatus: stdhttp.StatusUnauthorized},
		{name: "available coupons", method: stdhttp.MethodGet, path: "/api/v1/orders/coupons/available", wantStatus: stdhttp.StatusUnauthorized},
		{name: "instances list", method: stdhttp.MethodGet, path: "/api/v1/instances", wantStatus: stdhttp.StatusUnauthorized},
		{name: "instance detail", method: stdhttp.MethodGet, path: "/api/v1/instances/123", wantStatus: stdhttp.StatusUnauthorized},
		{name: "instance renew", method: stdhttp.MethodPost, path: "/api/v1/instances/123/renew", wantStatus: stdhttp.StatusUnauthorized},
		{name: "instance renew preview", method: stdhttp.MethodPost, path: "/api/v1/instances/123/renew/preview", wantStatus: stdhttp.StatusUnauthorized},
		{name: "instance refund preview", method: stdhttp.MethodGet, path: "/api/v1/instances/123/refund/preview", wantStatus: stdhttp.StatusUnauthorized},
		{name: "instance refund", method: stdhttp.MethodPost, path: "/api/v1/instances/123/refund", wantStatus: stdhttp.StatusUnauthorized},
		{name: "instance auto renew", method: stdhttp.MethodPatch, path: "/api/v1/instances/123/auto-renew", wantStatus: stdhttp.StatusUnauthorized},
		{name: "user me", method: stdhttp.MethodGet, path: "/api/v1/users/me", wantStatus: stdhttp.StatusUnauthorized},
		{name: "membership me", method: stdhttp.MethodGet, path: "/api/v1/membership/me", wantStatus: stdhttp.StatusUnauthorized},
		{name: "points center", method: stdhttp.MethodGet, path: "/api/v1/points/center", wantStatus: stdhttp.StatusUnauthorized},
		{name: "promotion me", method: stdhttp.MethodGet, path: "/api/v1/promotion/me", wantStatus: stdhttp.StatusUnauthorized},
		{name: "agent me", method: stdhttp.MethodGet, path: "/api/v1/agent/me", wantStatus: stdhttp.StatusUnauthorized},
		{name: "instance upgrade products", method: stdhttp.MethodGet, path: "/api/v1/instances/123/upgrade/products", wantStatus: stdhttp.StatusUnauthorized},
		{name: "instance disk quote", method: stdhttp.MethodPost, path: "/api/v1/instances/123/disks/quote", wantStatus: stdhttp.StatusUnauthorized},
		{name: "instance point claim", method: stdhttp.MethodPost, path: "/api/v1/instances/123/points/claim", wantStatus: stdhttp.StatusUnauthorized},
		{name: "instance real data history", method: stdhttp.MethodGet, path: "/api/v1/instances/123/real-data-history", wantStatus: stdhttp.StatusUnauthorized},
		{name: "instance suspend", method: stdhttp.MethodPost, path: "/api/v1/instances/123/suspend", wantStatus: stdhttp.StatusUnauthorized},
		{name: "admin user instance detail", method: stdhttp.MethodGet, path: "/api/v1/admin/users/7/instances/123", wantStatus: stdhttp.StatusUnauthorized},
		{name: "admin user instance nat acl", method: stdhttp.MethodGet, path: "/api/v1/admin/users/7/instances/123/nat-acl", wantStatus: stdhttp.StatusUnauthorized},
		{name: "admin user instance power", method: stdhttp.MethodPost, path: "/api/v1/admin/users/7/instances/123/power/reboot", wantStatus: stdhttp.StatusUnauthorized},
		{name: "admin user adjust balance", method: stdhttp.MethodPost, path: "/api/v1/admin/users/7/adjust-balance", wantStatus: stdhttp.StatusUnauthorized},
		{name: "admin user refund quota", method: stdhttp.MethodPost, path: "/api/v1/admin/users/7/refund-quota/add", wantStatus: stdhttp.StatusUnauthorized},
		{name: "admin user invite quota", method: stdhttp.MethodPost, path: "/api/v1/admin/users/7/invite-code-quota/add", wantStatus: stdhttp.StatusUnauthorized},
		{name: "admin user impersonate", method: stdhttp.MethodPost, path: "/api/v1/admin/users/7/impersonate", wantStatus: stdhttp.StatusUnauthorized},
		{name: "admin license status", method: stdhttp.MethodGet, path: "/api/v1/admin/license-status", wantStatus: stdhttp.StatusUnauthorized},
		{name: "admin license activate", method: stdhttp.MethodPost, path: "/api/v1/admin/license/activate", wantStatus: stdhttp.StatusUnauthorized},
		{name: "admin activities", method: stdhttp.MethodGet, path: "/api/v1/admin/activities", wantStatus: stdhttp.StatusUnauthorized},
		{name: "admin create activity", method: stdhttp.MethodPost, path: "/api/v1/admin/activities", wantStatus: stdhttp.StatusUnauthorized},
		{name: "security group rule old path", method: stdhttp.MethodPost, path: "/api/v1/security-groups/77/rules", wantStatus: stdhttp.StatusUnauthorized},
		{name: "recharge notify get", method: stdhttp.MethodGet, path: "/api/v1/recharge/notify", wantStatus: stdhttp.StatusServiceUnavailable},
		{name: "zjmf downstream host sync", method: stdhttp.MethodPost, path: "/api/host/sync", wantStatus: stdhttp.StatusOK},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			req := httptest.NewRequest(tt.method, tt.path, nil)
			rec := httptest.NewRecorder()

			router.ServeHTTP(rec, req)

			if rec.Code != tt.wantStatus {
				t.Fatalf("status = %d, want %d; body=%s", rec.Code, tt.wantStatus, rec.Body.String())
			}
		})
	}
}

func testLicenseEvaluator(t *testing.T) *licenseclient.Evaluator {
	t.Helper()
	publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
	if err != nil {
		t.Fatalf("generate license key: %v", err)
	}
	payload, err := json.Marshal(map[string]any{
		"status":     "active",
		"validUntil": time.Now().UTC().Add(time.Hour).Format(time.RFC3339),
		"expiresAt":  time.Now().UTC().Add(24 * time.Hour).Format(time.RFC3339),
		"license":    "AUTH-TEST",
		"licenseNo":  "LIC-TEST",
		"keyId":      "test-key",
		"instanceId": "550e8400-e29b-41d4-a716-446655440000",
		"sequence":   1,
		"features":   []string{licenseclient.FeatureHTTP, licenseclient.FeatureWorker, licenseclient.FeaturePlugins},
		"issuedAt":   time.Now().UTC().Unix(),
	})
	if err != nil {
		t.Fatalf("marshal license: %v", err)
	}
	signature := "SIGN-" + base64.RawURLEncoding.EncodeToString(ed25519.Sign(privateKey, payload))
	raw := append(append([]byte(nil), payload[:len(payload)-1]...), []byte(`,"signature":"`+signature+`"}`)...)
	eval := licenseclient.NewEvaluator(publicKey)
	if err := eval.LoadFromQuery(raw, signature); err != nil {
		t.Fatalf("load license: %v", err)
	}
	return eval
}
