package handlers

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

	"bookhoard/internal/database"

	"github.com/google/uuid"
	"github.com/jackc/pgx/v5/pgtype"
	"github.com/labstack/echo/v4"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestPreviewCollection_NoAuth(t *testing.T) {
	e := echo.New()
	handler := &CollectionHandler{}

	reqBody := map[string]interface{}{
		"library_id":      uuid.New().String(),
		"rules":           []map[string]interface{}{},
		"manual_book_ids": []string{},
		"limit":           20,
	}
	body, _ := json.Marshal(reqBody)

	req := httptest.NewRequest("POST", "/api/collections/preview", bytes.NewBuffer(body))
	req.Header.Set("Content-Type", "application/json")
	rec := httptest.NewRecorder()

	c := e.NewContext(req, rec)

	err := handler.PreviewCollection(c)
	assert.NoError(t, err)

	assert.Equal(t, http.StatusUnauthorized, rec.Code)
}

func TestPreviewCollection_MissingLibraryID(t *testing.T) {
	e := echo.New()
	handler := &CollectionHandler{}

	reqBody := map[string]interface{}{
		"library_id":      "",
		"rules":           []map[string]interface{}{},
		"manual_book_ids": []string{},
		"limit":           20,
	}
	body, _ := json.Marshal(reqBody)

	req := httptest.NewRequest("POST", "/api/collections/preview", bytes.NewBuffer(body))
	req.Header.Set("Content-Type", "application/json")
	rec := httptest.NewRecorder()

	// Mock user (would normally come from middleware)
	user := database.Users{
		ID: pgtype.UUID{Bytes: uuid.New(), Valid: true},
	}
	c := e.NewContext(req, rec)
	c.Set("user", user)

	err := handler.PreviewCollection(c)
	assert.NoError(t, err)

	assert.Equal(t, http.StatusBadRequest, rec.Code)
}

func TestPreviewCollection_InvalidLibraryID(t *testing.T) {
	e := echo.New()
	handler := &CollectionHandler{}

	reqBody := map[string]interface{}{
		"library_id":      "invalid-uuid",
		"rules":           []map[string]interface{}{},
		"manual_book_ids": []string{},
		"limit":           20,
	}
	body, _ := json.Marshal(reqBody)

	req := httptest.NewRequest("POST", "/api/collections/preview", bytes.NewBuffer(body))
	req.Header.Set("Content-Type", "application/json")
	rec := httptest.NewRecorder()

	// Mock user
	user := database.Users{
		ID: pgtype.UUID{Bytes: uuid.New(), Valid: true},
	}
	c := e.NewContext(req, rec)
	c.Set("user", user)

	err := handler.PreviewCollection(c)
	assert.NoError(t, err)

	assert.Equal(t, http.StatusBadRequest, rec.Code)
}

func TestPreviewCollection_LimitValidation(t *testing.T) {
	e := echo.New()
	handler := &CollectionHandler{}
	libraryID := uuid.New()

	tests := []struct {
		name           string
		limit          int
		expectedStatus int
	}{
		{
			name:           "valid limit 10",
			limit:          10,
			expectedStatus: http.StatusBadRequest, // No actual library, so will return error
		},
		{
			name:           "valid limit 20",
			limit:          20,
			expectedStatus: http.StatusBadRequest, // No actual library, so will return error
		},
		{
			name:           "limit too high (101)",
			limit:          101,
			expectedStatus: http.StatusBadRequest, // Limit validation
		},
		{
			name:           "limit zero",
			limit:          0,
			expectedStatus: http.StatusBadRequest, // Should default to 20, but library doesn't exist
		},
		{
			name:           "negative limit",
			limit:          -5,
			expectedStatus: http.StatusBadRequest, // No actual library
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			reqBody := map[string]interface{}{
				"library_id":      libraryID.String(),
				"rules":           []map[string]interface{}{},
				"manual_book_ids": []string{},
				"limit":           tt.limit,
			}
			body, _ := json.Marshal(reqBody)

			req := httptest.NewRequest("POST", "/api/collections/preview", bytes.NewBuffer(body))
			req.Header.Set("Content-Type", "application/json")
			rec := httptest.NewRecorder()

			// Mock user
			user := database.Users{
				ID: pgtype.UUID{Bytes: uuid.New(), Valid: true},
			}
			c := e.NewContext(req, rec)
			c.Set("user", user)

			err := handler.PreviewCollection(c)
			require.NoError(t, err)

			assert.Equal(t, tt.expectedStatus, rec.Code)
		})
	}
}

func TestPreviewCollection_RuleValidation(t *testing.T) {
	e := echo.New()
	handler := &CollectionHandler{}
	libraryID := uuid.New()

	tests := []struct {
		name           string
		rules          interface{}
		expectedStatus int
	}{
		{
			name:           "empty rules array",
			rules:          []map[string]interface{}{},
			expectedStatus: http.StatusBadRequest, // Library doesn't exist
		},
		{
			name: "valid rule structure",
			rules: []map[string]interface{}{
				{
					"id":       "rule1",
					"field":    "genre",
					"operator": "equals",
					"value":    "Sci-Fi",
					"priority": 1,
				},
			},
			expectedStatus: http.StatusBadRequest, // Library doesn't exist
		},
		{
			name: "multiple rules",
			rules: []map[string]interface{}{
				{
					"id":       "rule1",
					"field":    "genre",
					"operator": "equals",
					"value":    "Sci-Fi",
					"priority": 1,
				},
				{
					"id":       "rule2",
					"field":    "author",
					"operator": "contains",
					"value":    "Asimov",
					"priority": 2,
				},
			},
			expectedStatus: http.StatusBadRequest, // Library doesn't exist
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			reqBody := map[string]interface{}{
				"library_id":      libraryID.String(),
				"rules":           tt.rules,
				"manual_book_ids": []string{},
				"limit":           20,
			}
			body, _ := json.Marshal(reqBody)

			req := httptest.NewRequest("POST", "/api/collections/preview", bytes.NewBuffer(body))
			req.Header.Set("Content-Type", "application/json")
			rec := httptest.NewRecorder()

			// Mock user
			user := database.Users{
				ID: pgtype.UUID{Bytes: uuid.New(), Valid: true},
			}
			c := e.NewContext(req, rec)
			c.Set("user", user)

			err := handler.PreviewCollection(c)
			require.NoError(t, err)

			assert.Equal(t, tt.expectedStatus, rec.Code)
		})
	}
}

func TestPreviewCollection_ManualBookSelection(t *testing.T) {
	e := echo.New()
	handler := &CollectionHandler{}
	libraryID := uuid.New()

	reqBody := map[string]interface{}{
		"library_id": libraryID.String(),
		"rules":      []map[string]interface{}{},
		"manual_book_ids": []string{
			uuid.New().String(),
			uuid.New().String(),
			uuid.New().String(),
		},
		"limit": 20,
	}
	body, _ := json.Marshal(reqBody)

	req := httptest.NewRequest("POST", "/api/collections/preview", bytes.NewBuffer(body))
	req.Header.Set("Content-Type", "application/json")
	rec := httptest.NewRecorder()

	// Mock user
	user := database.Users{
		ID: pgtype.UUID{Bytes: uuid.New(), Valid: true},
	}
	c := e.NewContext(req, rec)
	c.Set("user", user)

	err := handler.PreviewCollection(c)
	require.NoError(t, err)

	// Should return 400 because library doesn't exist
	assert.Equal(t, http.StatusBadRequest, rec.Code)
}
