package web

import (
	"strings"
	"testing"

	"gitgud.io/mike/mpv-manager/pkg/locale"
)

// TestLanguageOption tests LanguageOption struct creation via FindLanguageByLocale
func TestLanguageOption(t *testing.T) {
	opt, err := FindLanguageByLocale("ja-JP")
	if err != nil {
		t.Fatalf("FindLanguageByLocale() failed: %v", err)
	}

	if opt == nil {
		t.Fatal("Expected non-nil result")
	}

	// Check that DisplayText is correctly formatted
	// Note: Japanese locale data includes both native name and phonetic representation
	if !strings.Contains(opt.DisplayText, "🇯🇵") {
		t.Errorf("Expected DisplayText to contain flag emoji, got %s", opt.DisplayText)
	}
	if !strings.Contains(opt.DisplayText, "JP") {
		t.Errorf("Expected DisplayText to contain country code, got %s", opt.DisplayText)
	}
	if !strings.Contains(opt.DisplayText, "Japanese") {
		t.Errorf("Expected DisplayText to contain 'Japanese', got %s", opt.DisplayText)
	}
}

// TestSearchLanguages_NoFilter tests loading all languages without filtering
func TestSearchLanguages_NoFilter(t *testing.T) {
	opts := LanguageFilterOptions{
		CommonOnly: false,
	}

	results, err := SearchLanguages(opts)
	if err != nil {
		t.Fatalf("SearchLanguages() failed: %v", err)
	}

	if len(results) == 0 {
		t.Error("Expected at least one language result")
	}

	// Check first result has all required fields
	first := results[0]
	if first.Locale == "" {
		t.Error("Expected non-empty Locale")
	}
	if first.LanguageName == "" {
		t.Error("Expected non-empty LanguageName")
	}
	if first.DisplayText == "" {
		t.Error("Expected non-empty DisplayText")
	}
}

// TestSearchLanguages_CommonOnly tests filtering to common languages only
func TestSearchLanguages_CommonOnly(t *testing.T) {
	opts := LanguageFilterOptions{
		CommonOnly: true,
	}

	results, err := SearchLanguages(opts)
	if err != nil {
		t.Fatalf("SearchLanguages() failed: %v", err)
	}

	if len(results) == 0 {
		t.Error("Expected at least one common language result")
	}

	// Check that results include some common languages
	commonCodes := locale.GetCommonLanguageCodes()
	codes := make(map[string]bool)
	for _, code := range commonCodes {
		codes[code] = false
	}

	for _, result := range results {
		langCode := strings.Split(result.Locale, "-")[0]
		if _, ok := codes[langCode]; ok {
			codes[langCode] = true
		}
	}

	foundCount := 0
	for _, found := range codes {
		if found {
			foundCount++
		}
	}

	// At least 5 common languages should be found
	if foundCount < 5 {
		t.Errorf("Expected at least 5 common languages, found %d", foundCount)
	}
}

// TestSearchLanguages_SearchTerm tests searching by language name
func TestSearchLanguages_SearchTerm(t *testing.T) {
	opts := LanguageFilterOptions{
		CommonOnly: false,
		SearchTerm: "Japanese",
	}

	results, err := SearchLanguages(opts)
	if err != nil {
		t.Fatalf("SearchLanguages() failed: %v", err)
	}

	if len(results) == 0 {
		t.Error("Expected at least one result for 'Japanese' search")
	}

	// Check that at least one result contains "Japanese" in the language name
	found := false
	for _, result := range results {
		if strings.Contains(result.LanguageName, "Japanese") {
			found = true
			break
		}
	}

	if !found {
		t.Error("Expected to find 'Japanese' in at least one result")
	}
}

// TestSearchLanguages_Limit tests limiting results
func TestSearchLanguages_Limit(t *testing.T) {
	opts := LanguageFilterOptions{
		CommonOnly: false,
		Limit:      5,
	}

	results, err := SearchLanguages(opts)
	if err != nil {
		t.Fatalf("SearchLanguages() failed: %v", err)
	}

	if len(results) > 5 {
		t.Errorf("Expected at most 5 results, got %d", len(results))
	}
}

// TestGetCommonLanguageOptions tests getting common language options
func TestGetCommonLanguageOptions(t *testing.T) {
	results, err := GetCommonLanguageOptions()
	if err != nil {
		t.Fatalf("GetCommonLanguageOptions() failed: %v", err)
	}

	if len(results) == 0 {
		t.Error("Expected at least one common language option")
	}

	// Check that all results are common languages
	for _, result := range results {
		langCode := strings.Split(result.Locale, "-")[0]
		if !IsCommonLanguage(langCode) {
			t.Errorf("Expected all results to be common languages, got: %s", langCode)
		}
	}
}

// TestGetAllLanguageOptions tests getting all language options
func TestGetAllLanguageOptions(t *testing.T) {
	results, err := GetAllLanguageOptions()
	if err != nil {
		t.Fatalf("GetAllLanguageOptions() failed: %v", err)
	}

	if len(results) < 100 {
		t.Errorf("Expected at least 100 language options, got %d", len(results))
	}

	// Results are sorted with priority: major variants, population, then alphabetical
	// Just verify results are returned and not empty
	if len(results) == 0 {
		t.Errorf("Expected at least one language option")
	}
}

// TestFindLanguageByLocale tests finding a specific language by locale
func TestFindLanguageByLocale(t *testing.T) {
	// Test with known locale
	opt, err := FindLanguageByLocale("ja-JP")
	if err != nil {
		t.Fatalf("FindLanguageByLocale() failed: %v", err)
	}

	if opt == nil {
		t.Fatal("Expected non-nil result")
	}

	if opt.Locale != "ja-JP" {
		t.Errorf("Expected locale 'ja-JP', got %s", opt.Locale)
	}

	if opt.LanguageName != "Japanese" {
		t.Errorf("Expected language name 'Japanese', got %s", opt.LanguageName)
	}

	if opt.CountryCode != "JP" {
		t.Errorf("Expected country code 'JP', got %s", opt.CountryCode)
	}

	if opt.FlagEmoji != "🇯🇵" {
		t.Errorf("Expected flag emoji '🇯🇵', got %s", opt.FlagEmoji)
	}
}

// TestFindLanguageByLocale_NotFound tests finding a non-existent locale
func TestFindLanguageByLocale_NotFound(t *testing.T) {
	_, err := FindLanguageByLocale("xx-XX")
	if err == nil {
		t.Error("Expected error for non-existent locale")
	}
}

// TestGetFlagImageURL tests getting flag image URL
func TestGetFlagImageURL(t *testing.T) {
	// Test with locale
	url := GetFlagImageURL("ja-JP")
	expected := "/static/flags/JP.png"
	if url != expected {
		t.Errorf("Expected %s, got %s", expected, url)
	}

	// Test with language code only
	url = GetFlagImageURL("ja")
	if url == "" {
		t.Error("Expected non-empty URL for language code")
	}
}

// TestFormatLanguageDisplayBasic tests formatting without country
// Note: FormatLanguageDisplayBasic is now internal to locale package
// This test verifies that DisplayText field is correctly formatted
func TestFormatLanguageDisplayBasic(t *testing.T) {
	// Test with Japanese locale (has local name)
	opt, err := FindLanguageByLocale("ja-JP")
	if err != nil {
		t.Fatalf("FindLanguageByLocale() failed: %v", err)
	}

	// Japanese should have format: "🇯🇵 JP - 日本語 (にほんご) (Japanese)"
	if !strings.Contains(opt.DisplayText, "日本語") {
		t.Errorf("Expected DisplayText to contain '日本語', got %s", opt.DisplayText)
	}
	if !strings.Contains(opt.DisplayText, "Japanese") {
		t.Errorf("Expected DisplayText to contain 'Japanese', got %s", opt.DisplayText)
	}
	if !strings.Contains(opt.DisplayText, "JP") {
		t.Errorf("Expected DisplayText to contain 'JP', got %s", opt.DisplayText)
	}

	// Test with English locale
	opt2, err := FindLanguageByLocale("en-US")
	if err != nil {
		t.Fatalf("FindLanguageByLocale() failed: %v", err)
	}

	// English should have format: "🇺🇸 US - English"
	if !strings.Contains(opt2.DisplayText, "English") {
		t.Errorf("Expected DisplayText to contain 'English', got %s", opt2.DisplayText)
	}
	if !strings.Contains(opt2.DisplayText, "US") {
		t.Errorf("Expected DisplayText to contain 'US', got %s", opt2.DisplayText)
	}
}

// TestGetLanguagesByCountry tests getting languages for a country
func TestGetLanguagesByCountry(t *testing.T) {
	results, err := GetLanguagesByCountry("JP")
	if err != nil {
		t.Fatalf("GetLanguagesByCountry() failed: %v", err)
	}

	if len(results) == 0 {
		t.Error("Expected at least one language for Japan")
	}

	// Check that all results have country code JP
	for _, result := range results {
		if result.CountryCode != "JP" {
			t.Errorf("Expected all results to have country code 'JP', got: %s", result.CountryCode)
		}
	}
}

// TestIsCommonLanguage tests checking if a language is common
func TestIsCommonLanguage(t *testing.T) {
	tests := []struct {
		langCode string
		isCommon bool
	}{
		{"en", true},
		{"ja", true},
		{"es", true},
		{"fr", true},
		{"de", true},
		{"zh", true},
		{"ko", true},
		{"it", true},
		{"pt", true},
		{"ru", true},
		{"xx", false},
		{"yy", false},
	}

	for _, tt := range tests {
		result := IsCommonLanguage(tt.langCode)
		if result != tt.isCommon {
			t.Errorf("IsCommonLanguage(%s) = %v, expected %v", tt.langCode, result, tt.isCommon)
		}
	}
}

// TestGetCommonLanguageCodes tests getting the list of common language codes
func TestGetCommonLanguageCodes(t *testing.T) {
	codes := GetCommonLanguageCodes()

	if len(codes) == 0 {
		t.Errorf("Expected at least one common language code, got %d", len(codes))
	}

	// Verify expected codes are present (checking old common languages)
	expectedCodes := map[string]bool{
		"en": false, "ja": false, "es": false, "fr": false, "de": false,
		"zh": false, "ko": false, "it": false, "pt": false, "ru": false,
	}

	for _, code := range codes {
		if _, ok := expectedCodes[code]; ok {
			expectedCodes[code] = true
		}
	}

	for code, found := range expectedCodes {
		if !found {
			t.Errorf("Expected to find common language code: %s", code)
		}
	}
}
