package main

import (
	"context"
	"testing"

	"bookhoard/internal/database"

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

// TestComicMetadataExtraction tests that comic metadata fields are stored correctly
func TestComicMetadataExtraction(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	ctx := context.Background()

	t.Run("CBZ with RTL manga", func(t *testing.T) {
		libraryID := setup.CreateLibrary(t, "RTL Manga Test Library", "comics")
		parsedLibraryID, err := uuid.Parse(libraryID)
		require.NoError(t, err, "Should parse library UUID")

		// Insert test media item with full comic metadata
		_, err = setup.DB.CreateMediaItem(ctx, database.CreateMediaItemParams{
			LibraryID:        pgtype.UUID{Bytes: parsedLibraryID, Valid: true},
			Title:            "Test Manga",
			FilePath:         "/test/manga.cbz",
			MangaType:        pgtype.Text{String: "yes_and_right_to_left", Valid: true},
			ReadingDirection: pgtype.Text{String: "rtl", Valid: true},
			SeriesCount:      pgtype.Int4{Int32: 12, Valid: true},
			Volume:           pgtype.Int4{Int32: 1, Valid: true},
			StoryArc:         pgtype.Text{String: "The Dark Phoenix Saga", Valid: true},
			AgeRating:        pgtype.Text{String: "Teen", Valid: true},
			CommunityRating:  pgtype.Float8{Float64: 8.5, Valid: true},
			Imprint:          pgtype.Text{String: "Shonen Jump", Valid: true},
			IsBlackAndWhite:  pgtype.Bool{Bool: false, Valid: true},
		})
		require.NoError(t, err)

		// Query it back
		items, err := setup.DB.ListMediaItemsByLibrary(ctx, pgtype.UUID{Bytes: parsedLibraryID, Valid: true})
		require.NoError(t, err)
		require.Greater(t, len(items), 0)

		item := items[0]
		assert.Equal(t, "Test Manga", item.Title)
		assert.Equal(t, "yes_and_right_to_left", item.MangaType.String)
		assert.Equal(t, "rtl", item.ReadingDirection.String)
		assert.Equal(t, int32(12), item.SeriesCount.Int32)
		assert.Equal(t, int32(1), item.Volume.Int32)
		assert.Equal(t, "The Dark Phoenix Saga", item.StoryArc.String)
		assert.Equal(t, "Teen", item.AgeRating.String)
		assert.Equal(t, 8.5, item.CommunityRating.Float64)
		assert.Equal(t, "Shonen Jump", item.Imprint.String)
		assert.False(t, item.IsBlackAndWhite.Bool)
	})

	t.Run("CBZ with Western comic", func(t *testing.T) {
		libraryID := setup.CreateLibrary(t, "Western Comic Test Library", "comics")
		parsedLibraryID, err := uuid.Parse(libraryID)
		require.NoError(t, err, "Should parse library UUID")

		_, err = setup.DB.CreateMediaItem(ctx, database.CreateMediaItemParams{
			LibraryID:        pgtype.UUID{Bytes: parsedLibraryID, Valid: true},
			Title:            "Test Comic",
			FilePath:         "/test/comic.cbz",
			MangaType:        pgtype.Text{String: "no", Valid: true},
			ReadingDirection: pgtype.Text{String: "ltr", Valid: true},
			Imprint:          pgtype.Text{String: "Vertigo", Valid: true},
			IsBlackAndWhite:  pgtype.Bool{Bool: true, Valid: true},
			StoryArc:         pgtype.Text{String: "Batman: Year One", Valid: true},
			SeriesCount:      pgtype.Int4{Int32: 4, Valid: true},
		})
		require.NoError(t, err)

		items, err := setup.DB.ListMediaItemsByLibrary(ctx, pgtype.UUID{Bytes: parsedLibraryID, Valid: true})
		require.NoError(t, err)

		item := items[0]
		assert.Equal(t, "no", item.MangaType.String)
		assert.Equal(t, "ltr", item.ReadingDirection.String)
		assert.Equal(t, "Vertigo", item.Imprint.String)
		assert.True(t, item.IsBlackAndWhite.Bool)
		assert.Equal(t, "Batman: Year One", item.StoryArc.String)
		assert.Equal(t, int32(4), item.SeriesCount.Int32)
	})

	t.Run("Comic with minimal metadata", func(t *testing.T) {
		libraryID := setup.CreateLibrary(t, "Minimal Metadata Test Library", "comics")
		parsedLibraryID, err := uuid.Parse(libraryID)
		require.NoError(t, err, "Should parse library UUID")

		_, err = setup.DB.CreateMediaItem(ctx, database.CreateMediaItemParams{
			LibraryID:        pgtype.UUID{Bytes: parsedLibraryID, Valid: true},
			Title:            "Minimal Comic",
			FilePath:         "/test/minimal.cbz",
			MangaType:        pgtype.Text{String: "unknown", Valid: true},
			ReadingDirection: pgtype.Text{String: "auto", Valid: true},
		})
		require.NoError(t, err)

		items, err := setup.DB.ListMediaItemsByLibrary(ctx, pgtype.UUID{Bytes: parsedLibraryID, Valid: true})
		require.NoError(t, err)

		item := items[0]
		assert.Equal(t, "Minimal Comic", item.Title)
		// Verify defaults
		assert.Equal(t, "unknown", item.MangaType.String)
		assert.Equal(t, "auto", item.ReadingDirection.String)
	})
}

// TestReadingDirectionAPI tests reading direction in API responses
func TestReadingDirectionAPI(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	ctx := context.Background()
	libraryID := setup.CreateLibrary(t, "Reading Direction Test Library", "comics")
	parsedLibraryID, err := uuid.Parse(libraryID)
	require.NoError(t, err, "Should parse library UUID")

	// Create test items with different reading directions
	testCases := []struct {
		title string
		manga string
		dir   string
	}{
		{"Japanese Manga", "yes_and_right_to_left", "rtl"},
		{"Western Comic", "no", "ltr"},
		{"Webtoon", "unknown", "auto"},
	}

	for _, tc := range testCases {
		_, err := setup.DB.CreateMediaItem(ctx, database.CreateMediaItemParams{
			LibraryID:        pgtype.UUID{Bytes: parsedLibraryID, Valid: true},
			Title:            tc.title,
			FilePath:         "/test/" + tc.title + ".cbz",
			MangaType:        pgtype.Text{String: tc.manga, Valid: true},
			ReadingDirection: pgtype.Text{String: tc.dir, Valid: true},
		})
		require.NoError(t, err)
	}

	t.Run("Search API includes reading_direction", func(t *testing.T) {
		items, err := setup.DB.ListMediaItemsByLibrary(ctx, pgtype.UUID{Bytes: parsedLibraryID, Valid: true})
		require.NoError(t, err)
		require.Len(t, items, 3)

		// Verify all items have reading direction set
		for _, item := range items {
			assert.NotEmpty(t, item.ReadingDirection.String)
			assert.NotEmpty(t, item.MangaType.String)
			assert.True(t, item.ReadingDirection.Valid)
		}
	})

	t.Run("Filter by reading_direction - RTL only", func(t *testing.T) {
		// Query all items and filter in-memory
		items, err := setup.DB.ListMediaItemsByLibrary(ctx, pgtype.UUID{Bytes: parsedLibraryID, Valid: true})
		require.NoError(t, err)

		// Count RTL items
		rtlCount := 0
		for _, item := range items {
			if item.ReadingDirection.String == "rtl" {
				rtlCount++
			}
		}
		assert.Equal(t, 1, rtlCount)
	})

	t.Run("Verify all reading directions present", func(t *testing.T) {
		items, err := setup.DB.ListMediaItemsByLibrary(ctx, pgtype.UUID{Bytes: parsedLibraryID, Valid: true})
		require.NoError(t, err)

		directions := make(map[string]bool)
		for _, item := range items {
			directions[item.ReadingDirection.String] = true
		}

		assert.True(t, directions["rtl"])
		assert.True(t, directions["ltr"])
		assert.True(t, directions["auto"])
	})
}

// TestUniversalMetadataFields tests universal fields apply to all formats
func TestUniversalMetadataFields(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	ctx := context.Background()

	// Test with both comic and ebook libraries
	comicLibraryID := setup.CreateLibrary(t, "Comic Test Library", "comics")
	ebookLibraryID := setup.CreateLibrary(t, "Ebook Test Library", "ebooks")
	parsedComicLibraryID, err := uuid.Parse(comicLibraryID)
	require.NoError(t, err, "Should parse comic library UUID")
	parsedEbookLibraryID, err := uuid.Parse(ebookLibraryID)
	require.NoError(t, err, "Should parse ebook library UUID")

	t.Run("Comic with universal fields", func(t *testing.T) {
		_, err := setup.DB.CreateMediaItem(ctx, database.CreateMediaItemParams{
			LibraryID:       pgtype.UUID{Bytes: parsedComicLibraryID, Valid: true},
			Title:           "Comic with Universal Metadata",
			FilePath:        "/test/comic.cbz",
			SeriesCount:     pgtype.Int4{Int32: 10, Valid: true},
			Volume:          pgtype.Int4{Int32: 2, Valid: true},
			Imprint:         pgtype.Text{String: "DC Black Label", Valid: true},
			AgeRating:       pgtype.Text{String: "Mature", Valid: true},
			WebUrl:          pgtype.Text{String: "https://example.com/comic", Valid: true},
			CommunityRating: pgtype.Float8{Float64: 9.2, Valid: true},
		})
		require.NoError(t, err)

		items, err := setup.DB.ListMediaItemsByLibrary(ctx, pgtype.UUID{Bytes: parsedComicLibraryID, Valid: true})
		require.NoError(t, err)

		item := items[0]
		assert.Equal(t, int32(10), item.SeriesCount.Int32)
		assert.Equal(t, int32(2), item.Volume.Int32)
		assert.Equal(t, "DC Black Label", item.Imprint.String)
		assert.Equal(t, "Mature", item.AgeRating.String)
		assert.Equal(t, "https://example.com/comic", item.WebUrl.String)
		assert.Equal(t, 9.2, item.CommunityRating.Float64)
	})

	t.Run("Ebook with universal fields", func(t *testing.T) {
		_, err := setup.DB.CreateMediaItem(ctx, database.CreateMediaItemParams{
			LibraryID:       pgtype.UUID{Bytes: parsedEbookLibraryID, Valid: true},
			Title:           "Ebook with Universal Metadata",
			FilePath:        "/test/book.epub",
			SeriesCount:     pgtype.Int4{Int32: 7, Valid: true},
			Volume:          pgtype.Int4{Int32: 1, Valid: true},
			Imprint:         pgtype.Text{String: "HarperCollins", Valid: true},
			AgeRating:       pgtype.Text{String: "Everyone", Valid: true},
			WebUrl:          pgtype.Text{String: "https://example.com/book", Valid: true},
			CommunityRating: pgtype.Float8{Float64: 4.5, Valid: true},
		})
		require.NoError(t, err)

		items, err := setup.DB.ListMediaItemsByLibrary(ctx, pgtype.UUID{Bytes: parsedEbookLibraryID, Valid: true})
		require.NoError(t, err)

		item := items[0]
		assert.Equal(t, int32(7), item.SeriesCount.Int32)
		assert.Equal(t, int32(1), item.Volume.Int32)
		assert.Equal(t, "HarperCollins", item.Imprint.String)
		assert.Equal(t, "Everyone", item.AgeRating.String)
		assert.Equal(t, "https://example.com/book", item.WebUrl.String)
		assert.Equal(t, 4.5, item.CommunityRating.Float64)
	})
}

// TestComicSpecificFields tests comic-specific fields
func TestComicSpecificFields(t *testing.T) {
	setup := setupDeviceTest(t)
	defer setup.Server.Close()

	ctx := context.Background()
	libraryID := setup.CreateLibrary(t, "Comic Test Library", "comics")
	parsedLibraryID, err := uuid.Parse(libraryID)
	require.NoError(t, err, "Should parse library UUID")

	t.Run("Alternate series info as JSONB", func(t *testing.T) {
		alternateInfo := `{"alternate_series":"Ultimate X-Men","alternate_number":1,"alternate_count":12}`

		_, err := setup.DB.CreateMediaItem(ctx, database.CreateMediaItemParams{
			LibraryID:       pgtype.UUID{Bytes: parsedLibraryID, Valid: true},
			Title:           "X-Men with Alternate Series",
			FilePath:        "/test/xmen.cbz",
			AlternateInfo:   []byte(alternateInfo),
			ScanInformation: pgtype.Text{String: "Scanned by Minutemen", Valid: true},
			Summary:         pgtype.Text{String: "Professor X creates mutant team", Valid: true},
			MetadataNotes:   pgtype.Text{String: "From collection", Valid: true},
		})
		require.NoError(t, err)

		items, err := setup.DB.ListMediaItemsByLibrary(ctx, pgtype.UUID{Bytes: parsedLibraryID, Valid: true})
		require.NoError(t, err)

		item := items[0]
		assert.NotNil(t, item.AlternateInfo)
		assert.JSONEq(t, alternateInfo, string(item.AlternateInfo))
		assert.Equal(t, "Scanned by Minutemen", item.ScanInformation.String)
		assert.Equal(t, "Professor X creates mutant team", item.Summary.String)
		assert.Equal(t, "From collection", item.MetadataNotes.String)
	})
}
