package main

import (
	"bookhoard/internal/handlers"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestFilterByStatus(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&status=50", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should filter by status")
}

func TestFilterByGenre(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&genre_filter=Fiction", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should filter by genre")
}

func TestFilterByLanguage(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&genre_filter=Fiction&language_filter=en", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should filter by language")
}

func TestFilterByCollection(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")
	collection := setup.CreateCollection(t, "Test Collection")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&collection_id="+collection, nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should filter by collection")
}

func TestFilterByHasCover(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&has_cover=true", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should filter by has_cover")
}

func TestFilterByTags(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&tags=classic", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should filter by tags")
}

func TestFilterBySpecialCharacters(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&special_characters=;", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should handle special characters")
}

func TestFilterCombineMultipleFilters(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&genre_filter=Fiction&language_filter=en&year_min=2000&year_max=2020", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should combine multiple filters")

	var response handlers.SearchMediaItemsResponse
	err := json.Unmarshal(rec.Body.Bytes(), &response)
	require.NoError(t, err, "Should unmarshal filtered response")
	assert.GreaterOrEqual(t, len(response.Results), 0, "Should have at least one result")
}

func TestFilterPagination(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&limit=2&offset=0", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should handle pagination")
}

func TestFilterNoFilters(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID, nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should handle no filters")
}

func TestFilterSortingByTitle(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&sort=title+ASC", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should sort by title")

	var response handlers.SearchMediaItemsResponse
	err := json.Unmarshal(rec.Body.Bytes(), &response)
	require.NoError(t, err, "Should unmarshal filtered response")
	assert.GreaterOrEqual(t, response.Total, 0, "Should return all items")
}

func TestFilterSortingByAuthor(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&sort=author+DESC", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should sort by author")
}

func TestFilterSortingByDateAdded(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&sort=date_added+DESC", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should sort by date added")
}

func TestFilterSortingByLastRead(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&sort=last_read+DESC", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should sort by last read")
}

func TestFilterWithLibraryID(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID, nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should filter with library_id")

	var response handlers.SearchMediaItemsResponse
	err := json.Unmarshal(rec.Body.Bytes(), &response)
	require.NoError(t, err, "Should unmarshal filtered response")
	assert.GreaterOrEqual(t, response.Total, 0, "Should return all items")
}

func TestFilterWithYearRange(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&year_min=2000&year_max=2020", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should filter by year range")
}

func TestFilterWithRating(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&rating_min=4", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should filter by rating")
}

func TestFilterWithProgress(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&progress_min=50&progress_max=100", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should filter by progress")
}

func TestFilterWithMultipleSorts(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&sort=author+ASC&sort=title+ASC", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should handle multiple sorts")
}

func TestFilterEdgeCases(t *testing.T) {
	t.Run("Empty library_id", func(t *testing.T) {
		setup := setupDeviceTest(t)
		defer setup.Server.Close()

		_ = setup.CreateLibrary(t, "Test Filter Library", "ebooks")
		_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

		req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id=", nil)
		req.Header.Set("Authorization", "Bearer "+setup.UserToken)
		rec := httptest.NewRecorder()
		setup.Server.Config.Handler.ServeHTTP(rec, req)

		assert.Equal(t, http.StatusBadRequest, rec.Code, "Should reject empty library_id")
	})

	t.Run("Invalid sort order", func(t *testing.T) {
		setup := setupDeviceTest(t)
		defer setup.Server.Close()

		libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
		_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

		req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&sort=title+INVALID", nil)
		req.Header.Set("Authorization", "Bearer "+setup.UserToken)
		rec := httptest.NewRecorder()
		setup.Server.Config.Handler.ServeHTTP(rec, req)

		assert.Equal(t, http.StatusOK, rec.Code, "Should handle invalid sort order gracefully")
	})

	t.Run("Negative offset", func(t *testing.T) {
		setup := setupDeviceTest(t)
		defer setup.Server.Close()

		libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
		_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

		req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&offset=-1", nil)
		req.Header.Set("Authorization", "Bearer "+setup.UserToken)
		rec := httptest.NewRecorder()
		setup.Server.Config.Handler.ServeHTTP(rec, req)

		assert.Equal(t, http.StatusOK, rec.Code, "Should handle negative offset")
	})

	t.Run("Zero limit", func(t *testing.T) {
		setup := setupDeviceTest(t)
		defer setup.Server.Close()

		libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
		_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

		req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&limit=0", nil)
		req.Header.Set("Authorization", "Bearer "+setup.UserToken)
		rec := httptest.NewRecorder()
		setup.Server.Config.Handler.ServeHTTP(rec, req)

		assert.Equal(t, http.StatusOK, rec.Code, "Should handle zero limit")
	})
}

func TestFilterWithTextSearch(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&search=Test", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should filter with text search")
}

func TestFilterWithAuthorSearch(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&author=Test", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should filter with author search")
}

func TestFilterWithSeriesFilter(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&series=Test", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should filter by series")
}

func TestFilterWithPublisherFilter(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&publisher=Test", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should filter by publisher")
}

func TestFilterWithFavorites(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&favorites=true", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should filter favorites")
}

func TestFilterArchivedItems(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	libraryID := setup.CreateLibrary(t, "Test Filter Library", "ebooks")
	_ = setup.CreateDevice(t, "Test Filter Device", "koreader", "filter-test-123")

	req := httptest.NewRequest("GET", "/api/media-items/filtered?library_id="+libraryID+"&archived=false", nil)
	req.Header.Set("Authorization", "Bearer "+setup.UserToken)
	rec := httptest.NewRecorder()
	setup.Server.Config.Handler.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code, "Should filter archived items")
}
