package admin

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/Wei-Shaw/sub2api/internal/service"
	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
)

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

	handler := &SoraHandler{}

	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = httptest.NewRequest(http.MethodGet, "/admin/sora/generations", nil)

	handler.ListGenerations(c)

	assert.Equal(t, http.StatusOK, w.Code)
	assert.Contains(t, w.Body.String(), "items")
}

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

	handler := &SoraHandler{}

	testCases := []struct {
		name     string
		userID   string
		expected int
	}{
		{"empty string", "", http.StatusBadRequest},
		{"non-numeric", "abc", http.StatusBadRequest},
		{"float", "1.5", http.StatusBadRequest},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			w := httptest.NewRecorder()
			c, _ := gin.CreateTestContext(w)
			c.Request = httptest.NewRequest(http.MethodDelete, "/admin/sora/users/"+tc.userID+"/storage", nil)
			c.Params = gin.Params{{Key: "id", Value: tc.userID}}

			handler.ClearUserStorage(c)

			assert.Equal(t, tc.expected, w.Code)
		})
	}
}

func TestSoraSystemStatsResponse_Fields(t *testing.T) {
	resp := SoraSystemStatsResponse{
		TotalUsers:        10,
		TotalGenerations:  100,
		TotalStorageBytes: 1024 * 1024 * 1024,
		ActiveGenerations: 5,
		ByStatus:          map[string]int64{"completed": 80, "failed": 20},
		ByModel:           map[string]int64{"sora2": 50, "sora1": 50},
	}

	assert.Equal(t, int64(10), resp.TotalUsers)
	assert.Equal(t, int64(100), resp.TotalGenerations)
	assert.Equal(t, int64(1024*1024*1024), resp.TotalStorageBytes)
	assert.Equal(t, int64(5), resp.ActiveGenerations)
	assert.Equal(t, int64(80), resp.ByStatus["completed"])
	assert.Equal(t, int64(50), resp.ByModel["sora2"])
}

func TestSoraUserStatsResponse_Fields(t *testing.T) {
	resp := SoraUserStatsResponse{
		UserID:             1,
		Username:           "testuser",
		Email:              "test@example.com",
		QuotaBytes:         10 * 1024 * 1024 * 1024,
		UsedBytes:          1 * 1024 * 1024 * 1024,
		AvailableBytes:     9 * 1024 * 1024 * 1024,
		QuotaSource:        "user",
		GenerationsCount:   10,
		ActiveCount:        2,
		TotalFileSizeBytes: 1 * 1024 * 1024 * 1024,
	}

	assert.Equal(t, int64(1), resp.UserID)
	assert.Equal(t, "testuser", resp.Username)
	assert.Equal(t, "test@example.com", resp.Email)
	assert.Equal(t, int64(10*1024*1024*1024), resp.QuotaBytes)
	assert.Equal(t, int64(1*1024*1024*1024), resp.UsedBytes)
	assert.Equal(t, "user", resp.QuotaSource)
	assert.Equal(t, int64(10), resp.GenerationsCount)
	assert.Equal(t, int64(2), resp.ActiveCount)
}

func TestSoraGenerationAdminResponse_Fields(t *testing.T) {
	completedAt := "2024-01-01T12:00:00Z"
	resp := SoraGenerationAdminResponse{
		ID:            1,
		UserID:        100,
		Username:      "testuser",
		Email:         "test@example.com",
		Model:         "sora2",
		Prompt:        "A beautiful sunset",
		MediaType:     "video",
		Status:        "completed",
		StorageType:   "s3",
		MediaURL:      "https://example.com/video.mp4",
		FileSizeBytes: 1024 * 1024 * 10,
		ErrorMessage:  "",
		CreatedAt:     "2024-01-01T10:00:00Z",
		CompletedAt:   &completedAt,
	}

	assert.Equal(t, int64(1), resp.ID)
	assert.Equal(t, int64(100), resp.UserID)
	assert.Equal(t, "testuser", resp.Username)
	assert.Equal(t, "sora2", resp.Model)
	assert.Equal(t, "video", resp.MediaType)
	assert.Equal(t, "completed", resp.Status)
	assert.Equal(t, "s3", resp.StorageType)
	assert.Equal(t, int64(1024*1024*10), resp.FileSizeBytes)
	assert.NotNil(t, resp.CompletedAt)
}

func TestSoraGenerationAdminResponse_NilCompletedAt(t *testing.T) {
	resp := SoraGenerationAdminResponse{
		ID:          1,
		UserID:      100,
		Username:    "testuser",
		Email:       "test@example.com",
		Model:       "sora2",
		Prompt:      "A beautiful sunset",
		MediaType:   "video",
		Status:      "pending",
		StorageType: "upstream",
		CreatedAt:   "2024-01-01T10:00:00Z",
		CompletedAt: nil,
	}

	assert.Equal(t, "pending", resp.Status)
	assert.Nil(t, resp.CompletedAt)
}

func TestNewSoraHandler(t *testing.T) {
	handler := NewSoraHandler(nil, nil, nil)
	assert.NotNil(t, handler)
	assert.Nil(t, handler.soraGenService)
	assert.Nil(t, handler.soraQuotaService)
	assert.Nil(t, handler.userRepo)
}

func TestUser_SoraFields(t *testing.T) {
	user := &service.User{
		ID:                    1,
		Email:                 "test@example.com",
		SoraStorageQuotaBytes: 10 * 1024 * 1024 * 1024,
		SoraStorageUsedBytes:  1 * 1024 * 1024 * 1024,
	}

	assert.Equal(t, int64(1), user.ID)
	assert.Equal(t, int64(10*1024*1024*1024), user.SoraStorageQuotaBytes)
	assert.Equal(t, int64(1*1024*1024*1024), user.SoraStorageUsedBytes)
}

func TestQuotaInfo_Fields(t *testing.T) {
	quota := &service.QuotaInfo{
		QuotaBytes:     10 * 1024 * 1024 * 1024,
		UsedBytes:      1 * 1024 * 1024 * 1024,
		AvailableBytes: 9 * 1024 * 1024 * 1024,
		QuotaSource:    "user",
	}

	assert.Equal(t, int64(10*1024*1024*1024), quota.QuotaBytes)
	assert.Equal(t, int64(1*1024*1024*1024), quota.UsedBytes)
	assert.Equal(t, "user", quota.QuotaSource)
}

func TestSoraSystemStatsResponse_JSON(t *testing.T) {
	resp := SoraSystemStatsResponse{
		TotalUsers:        10,
		TotalGenerations:  100,
		TotalStorageBytes: 1024,
		ActiveGenerations: 5,
		ByStatus:          map[string]int64{"completed": 80},
		ByModel:           map[string]int64{"sora2": 50},
	}

	// Verify JSON tags by checking field values
	assert.Equal(t, int64(10), resp.TotalUsers)
	assert.Equal(t, int64(100), resp.TotalGenerations)
	assert.Equal(t, int64(1024), resp.TotalStorageBytes)
	assert.Equal(t, int64(5), resp.ActiveGenerations)
}

func TestSoraUserStatsResponse_JSON(t *testing.T) {
	resp := SoraUserStatsResponse{
		UserID:             1,
		Username:           "testuser",
		Email:              "test@example.com",
		QuotaBytes:         1024,
		UsedBytes:          512,
		AvailableBytes:     512,
		QuotaSource:        "user",
		GenerationsCount:   10,
		ActiveCount:        2,
		TotalFileSizeBytes: 1024,
	}

	// Verify all fields
	assert.Equal(t, int64(1), resp.UserID)
	assert.Equal(t, "testuser", resp.Username)
	assert.Equal(t, "test@example.com", resp.Email)
	assert.Equal(t, int64(1024), resp.QuotaBytes)
	assert.Equal(t, int64(512), resp.UsedBytes)
	assert.Equal(t, int64(512), resp.AvailableBytes)
	assert.Equal(t, "user", resp.QuotaSource)
	assert.Equal(t, int64(10), resp.GenerationsCount)
	assert.Equal(t, int64(2), resp.ActiveCount)
	assert.Equal(t, int64(1024), resp.TotalFileSizeBytes)
}

func TestSoraSystemStatsResponse_EmptyMaps(t *testing.T) {
	resp := SoraSystemStatsResponse{
		TotalUsers:        0,
		TotalGenerations:  0,
		TotalStorageBytes: 0,
		ActiveGenerations: 0,
		ByStatus:          map[string]int64{},
		ByModel:           map[string]int64{},
	}

	assert.Equal(t, int64(0), resp.TotalUsers)
	assert.Equal(t, int64(0), resp.TotalGenerations)
	assert.Equal(t, int64(0), resp.TotalStorageBytes)
	assert.Equal(t, int64(0), resp.ActiveGenerations)
	assert.NotNil(t, resp.ByStatus)
	assert.NotNil(t, resp.ByModel)
}

func TestSoraUserStatsResponse_QuotaSources(t *testing.T) {
	sources := []string{"user", "group", "system", "unlimited"}

	for _, source := range sources {
		resp := SoraUserStatsResponse{
			UserID:      1,
			QuotaSource: source,
		}

		assert.Equal(t, source, resp.QuotaSource)
	}
}

func TestSoraGenerationAdminResponse_Statuses(t *testing.T) {
	statuses := []string{"pending", "generating", "completed", "failed", "cancelled"}

	for _, status := range statuses {
		resp := SoraGenerationAdminResponse{
			ID:     1,
			Status: status,
		}

		assert.Equal(t, status, resp.Status)
	}
}

func TestSoraGenerationAdminResponse_MediaTypes(t *testing.T) {
	mediaTypes := []string{"video", "image"}

	for _, mt := range mediaTypes {
		resp := SoraGenerationAdminResponse{
			ID:        1,
			MediaType: mt,
		}

		assert.Equal(t, mt, resp.MediaType)
	}
}

func TestSoraGenerationAdminResponse_StorageTypes(t *testing.T) {
	storageTypes := []string{"s3", "upstream"}

	for _, st := range storageTypes {
		resp := SoraGenerationAdminResponse{
			ID:          1,
			StorageType: st,
		}

		assert.Equal(t, st, resp.StorageType)
	}
}
