package services

import (
	"testing"

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

// TestMediaScanner_LibraryTypeAwareScanning tests library-type-aware scanning
func TestMediaScanner_LibraryTypeAwareScanning(t *testing.T) {
	t.Run("isScannableFile checks library type restrictions", func(t *testing.T) {
		scanner := &MediaScanner{
			folders: []string{"/test/ebooks", "/test/comics"},
			libraryTypes: map[string][]string{
				"/test/ebooks": {".epub", ".mobi", ".azw3"},
				"/test/comics": {".cbz", ".cbr", ".cb7", ".cbt"},
			},
		}

		tests := []struct {
			name     string
			filePath string
			expected bool
		}{
			{
				name:     "EPUB in ebooks folder",
				filePath: "/test/ebooks/book.epub",
				expected: true,
			},
			{
				name:     "MOBI in ebooks folder",
				filePath: "/test/ebooks/book.mobi",
				expected: true,
			},
			{
				name:     "CBZ in ebooks folder (should be rejected)",
				filePath: "/test/ebooks/comic.cbz",
				expected: false,
			},
			{
				name:     "CBZ in comics folder",
				filePath: "/test/comics/issue.cbz",
				expected: true,
			},
			{
				name:     "CBR in comics folder",
				filePath: "/test/comics/issue.cbr",
				expected: true,
			},
			{
				name:     "EPUB in comics folder (should be rejected)",
				filePath: "/test/comics/book.epub",
				expected: false,
			},
			{
				name:     "File outside watched folders",
				filePath: "/other/path/file.epub",
				expected: false,
			},
			{
				name:     "Unknown extension in ebooks folder",
				filePath: "/test/ebooks/file.pdf",
				expected: false,
			},
		}

		for _, tt := range tests {
			t.Run(tt.name, func(t *testing.T) {
				result := scanner.isScannableFile(tt.filePath)
				assert.Equal(t, tt.expected, result, "isScannableFile(%s) should return %v", tt.filePath, tt.expected)
			})
		}
	})

	t.Run("isScannableFile case insensitive", func(t *testing.T) {
		scanner := &MediaScanner{
			folders: []string{"/test/ebooks"},
			libraryTypes: map[string][]string{
				"/test/ebooks": {".epub"},
			},
		}

		tests := []struct {
			name     string
			filePath string
			expected bool
		}{
			{"Lowercase extension", "/test/ebooks/book.epub", true},
			{"Uppercase extension", "/test/ebooks/book.EPUB", true},
			{"Mixed case extension", "/test/ebooks/book.Epub", true},
		}

		for _, tt := range tests {
			t.Run(tt.name, func(t *testing.T) {
				result := scanner.isScannableFile(tt.filePath)
				assert.Equal(t, tt.expected, result)
			})
		}
	})

	t.Run("isScannableFile with no library type info", func(t *testing.T) {
		scanner := &MediaScanner{
			folders:      []string{"/test/ebooks"},
			libraryTypes: map[string][]string{}, // Empty library types
		}

		result := scanner.isScannableFile("/test/ebooks/book.epub")
		assert.False(t, result, "Should reject files when library type info is missing")
	})

	t.Run("isScannableFile handles subdirectories", func(t *testing.T) {
		scanner := &MediaScanner{
			folders: []string{"/test/ebooks"},
			libraryTypes: map[string][]string{
				"/test/ebooks": {".epub"},
			},
		}

		result := scanner.isScannableFile("/test/ebooks/subdir/book.epub")
		assert.True(t, result, "Should accept files in subdirectories")
	})
}

// TestMediaScanner_SetFolders_BuildsLibraryTypeCache tests SetFolders builds cache
func TestMediaScanner_SetFolders_BuildsLibraryTypeCache(t *testing.T) {
	// This is a unit test that verifies SetFolders properly initializes the libraryTypes cache
	// Full integration testing would require a mock database

	t.Run("SetFolders initializes libraryTypes map", func(t *testing.T) {
		scanner := &MediaScanner{
			libraryTypes: nil,
		}

		// Simulate SetFolders initialization
		scanner.libraryTypes = make(map[string][]string)
		assert.NotNil(t, scanner.libraryTypes, "libraryTypes should be initialized")
		assert.Equal(t, 0, len(scanner.libraryTypes), "libraryTypes should be empty initially")
	})

	t.Run("SetFolders clears old library types", func(t *testing.T) {
		scanner := &MediaScanner{
			libraryTypes: map[string][]string{
				"/old/folder": {".epub"},
			},
		}

		// Simulate SetFolders clearing and rebuilding
		scanner.libraryTypes = make(map[string][]string)
		assert.Equal(t, 0, len(scanner.libraryTypes), "Old library types should be cleared")
	})
}

// TestMediaScanner_LibraryTypeCrossContamination tests prevents cross-contamination
func TestMediaScanner_LibraryTypeCrossContamination(t *testing.T) {
	t.Run("Ebook library rejects comic formats", func(t *testing.T) {
		scanner := &MediaScanner{
			folders: []string{"/library/ebooks"},
			libraryTypes: map[string][]string{
				"/library/ebooks": {".epub", ".mobi", ".azw3", ".pdf"},
			},
		}

		comicFormats := []string{".cbz", ".cbr", ".cb7", ".cbt"}
		for _, ext := range comicFormats {
			filePath := "/library/ebooks/comic" + ext
			result := scanner.isScannableFile(filePath)
			assert.False(t, result, "Ebook library should reject %s files", ext)
		}
	})

	t.Run("Comic library rejects ebook formats", func(t *testing.T) {
		scanner := &MediaScanner{
			folders: []string{"/library/comics"},
			libraryTypes: map[string][]string{
				"/library/comics": {".cbz", ".cbr", ".cb7", ".cbt"},
			},
		}

		ebookFormats := []string{".epub", ".mobi", ".azw3", ".pdf", ".djvu"}
		for _, ext := range ebookFormats {
			filePath := "/library/comics/book" + ext
			result := scanner.isScannableFile(filePath)
			assert.False(t, result, "Comic library should reject %s files", ext)
		}
	})
}

// TestMediaScanner_MultipleLibraryTypes tests multiple libraries with different types
func TestMediaScanner_MultipleLibraryTypes(t *testing.T) {
	scanner := &MediaScanner{
		folders: []string{
			"/library/ebooks",
			"/library/comics",
			"/library/manga",
		},
		libraryTypes: map[string][]string{
			"/library/ebooks": {".epub", ".mobi", ".azw3"},
			"/library/comics": {".cbz", ".cbr"},
			"/library/manga":  {".cbz", ".cb7"}, // Manga uses CBZ and CB7
		},
	}

	tests := []struct {
		name     string
		filePath string
		expected bool
		reason   string
	}{
		{
			name:     "EPUB in ebook library",
			filePath: "/library/ebooks/novel.epub",
			expected: true,
			reason:   "EPUB allowed in ebook library",
		},
		{
			name:     "CBZ in comic library",
			filePath: "/library/comics/superman.cbz",
			expected: true,
			reason:   "CBZ allowed in comic library",
		},
		{
			name:     "CBZ in manga library",
			filePath: "/library/manga/naruto.cbz",
			expected: true,
			reason:   "CBZ allowed in manga library",
		},
		{
			name:     "CB7 in manga library",
			filePath: "/library/manga/onepiece.cb7",
			expected: true,
			reason:   "CB7 allowed in manga library",
		},
		{
			name:     "CB7 in comic library (rejected)",
			filePath: "/library/comics/batman.cb7",
			expected: false,
			reason:   "CB7 not allowed in comic library",
		},
		{
			name:     "EPUB in comic library (rejected)",
			filePath: "/library/comics/novel.epub",
			expected: false,
			reason:   "EPUB not allowed in comic library",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := scanner.isScannableFile(tt.filePath)
			assert.Equal(t, tt.expected, result, tt.reason)
		})
	}
}
