package account

import (
	"regexp"
	"strings"
	"testing"
	"unicode/utf8"
)

// TestTelegramSeed covers the pure mapping from Telegram launch fields to the
// create-time account seed: supported-language detection (bare and region-tagged),
// the real-name → @username (verbatim) → placeholder display-name precedence, and
// the sanitization of the real name (emoji, digits, punctuation stripped to the
// editable format). The username, when used, is kept verbatim.
func TestTelegramSeed(t *testing.T) {
	cases := map[string]struct {
		languageCode, username, firstName string
		wantLang, wantName                string
	}{
		"ru bare":             {"ru", "user", "Иван", "ru", "Иван"},
		"en region-tagged":    {"en-US", "user", "John", "en", "John"},
		"ru region-tagged":    {"ru-RU", "", "Пётр", "ru", "Пётр"},
		"unknown language":    {"fr", "frodo", "Frodo", "", "Frodo"},
		"empty language":      {"", "neo", "Neo", "", "Neo"},
		"first name wins":     {"en", "handle", "Real Name", "en", "Real Name"},
		"username fallback":   {"en", "handle", "", "en", "handle"},
		"trimmed":             {" RU ", "  ", "  Anna  ", "ru", "Anna"},
		"emoji stripped":      {"en", "user", "🎮Kaya🎮", "en", "Kaya"},
		"punct to space":      {"en", "user", "John❤Doe", "en", "John Doe"},
		"digits dropped":      {"ru", "user", "Маша123", "ru", "Маша"},
		"garbage to username": {"en", "good", "123!@#", "en", "good"},
		"username verbatim":   {"en", "co_ol99", "🎮🎮", "en", "co_ol99"},
	}
	for name, tc := range cases {
		t.Run(name, func(t *testing.T) {
			got := telegramSeed(tc.languageCode, tc.username, tc.firstName)
			if got.preferredLanguage != tc.wantLang {
				t.Errorf("preferredLanguage = %q, want %q", got.preferredLanguage, tc.wantLang)
			}
			if got.displayName != tc.wantName {
				t.Errorf("displayName = %q, want %q", got.displayName, tc.wantName)
			}
		})
	}
}

// TestTelegramSeedPlaceholder checks that a name with no usable letters falls back to
// a generated placeholder in the seeded language ("Player-NNNNN" / "Игрок-NNNNN").
func TestTelegramSeedPlaceholder(t *testing.T) {
	cases := map[string]struct {
		languageCode, username, firstName string
		wantRe                            string
	}{
		"en empty":                  {"en", "", "", `^Player-\d{5}$`},
		"ru empty":                  {"ru", "", "", `^Игрок-\d{5}$`},
		"default en":                {"fr", "", "", `^Player-\d{5}$`},
		"name garbage, no username": {"ru", "", "!!!", `^Игрок-\d{5}$`},
	}
	for name, tc := range cases {
		t.Run(name, func(t *testing.T) {
			got := telegramSeed(tc.languageCode, tc.username, tc.firstName).displayName
			if !regexp.MustCompile(tc.wantRe).MatchString(got) {
				t.Errorf("displayName = %q, want match %s", got, tc.wantRe)
			}
		})
	}
}

// TestTelegramSeedTruncatesLongName checks an over-long Telegram name is capped to
// maxDisplayName runes (counted in runes, not bytes).
func TestTelegramSeedTruncatesLongName(t *testing.T) {
	long := strings.Repeat("я", maxDisplayName+5)
	got := telegramSeed("ru", "", long)
	if n := utf8.RuneCountInString(got.displayName); n != maxDisplayName {
		t.Errorf("display name rune count = %d, want %d", n, maxDisplayName)
	}
}

// TestVKSeed covers the pure mapping from VK launch fields to the create-time account
// seed: supported-language detection from vk_language (bare and region-tagged) and the
// display name sanitized from the client-supplied name. Unlike Telegram there is no
// @username fallback — VK provides only the name.
func TestVKSeed(t *testing.T) {
	cases := map[string]struct {
		languageCode, displayName string
		wantLang, wantName        string
	}{
		"ru bare":          {"ru", "Иван", "ru", "Иван"},
		"en region-tagged": {"en-US", "John", "en", "John"},
		"full name kept":   {"ru", "Иван Петров", "ru", "Иван Петров"},
		"unknown language": {"uk", "Тарас", "", "Тарас"},
		"empty language":   {"", "Neo", "", "Neo"},
		"trimmed":          {" RU ", "  Anna  ", "ru", "Anna"},
		"emoji stripped":   {"en", "🎮Kaya🎮", "en", "Kaya"},
	}
	for name, tc := range cases {
		t.Run(name, func(t *testing.T) {
			got := vkSeed(tc.languageCode, tc.displayName)
			if got.preferredLanguage != tc.wantLang {
				t.Errorf("preferredLanguage = %q, want %q", got.preferredLanguage, tc.wantLang)
			}
			if got.displayName != tc.wantName {
				t.Errorf("displayName = %q, want %q", got.displayName, tc.wantName)
			}
		})
	}
}

// TestVKSeedPlaceholder checks a VK name with no usable letters falls back to a
// generated placeholder in the seeded language ("Player-NNNNN" / "Игрок-NNNNN").
func TestVKSeedPlaceholder(t *testing.T) {
	cases := map[string]struct {
		languageCode, displayName string
		wantRe                    string
	}{
		"en empty":     {"en", "", `^Player-\d{5}$`},
		"ru empty":     {"ru", "", `^Игрок-\d{5}$`},
		"default en":   {"uk", "", `^Player-\d{5}$`},
		"name garbage": {"ru", "123!@#", `^Игрок-\d{5}$`},
	}
	for name, tc := range cases {
		t.Run(name, func(t *testing.T) {
			got := vkSeed(tc.languageCode, tc.displayName).displayName
			if !regexp.MustCompile(tc.wantRe).MatchString(got) {
				t.Errorf("displayName = %q, want match %s", got, tc.wantRe)
			}
		})
	}
}
