package main

import "strings"

// regionFromLocale extracts the ISO 3166-1 alpha-2 region from a BCP-47 locale
// tag such as the value of navigator.language ("en-AU" -> "AU", "zh-Hans-CN" ->
// "CN"). The first subtag is the language unless it is itself an uppercase
// 2-letter region (a bare "AU"). Returns "" when no region subtag is present
// ("en" -> "").
func regionFromLocale(locale string) string {
	locale = strings.TrimSpace(locale)
	if locale == "" {
		return ""
	}
	parts := strings.FieldsFunc(locale, func(r rune) bool { return r == '-' || r == '_' })
	for i, part := range parts {
		if len(part) != 2 || !isASCIILetters(part) {
			continue // language (handled below), script ("Hans"), or variant
		}
		// Subtag 0 is the language unless it is already an uppercase region.
		if i == 0 && part != strings.ToUpper(part) {
			continue
		}
		return strings.ToUpper(part)
	}
	return ""
}

// isASCIILetters reports whether s is non-empty and all ASCII letters.
func isASCIILetters(s string) bool {
	if s == "" {
		return false
	}
	for _, r := range s {
		if (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') {
			return false
		}
	}
	return true
}

// tzRegions maps IANA timezones to ISO 3166-1 alpha-2 regions for the common,
// unambiguous cases. The device timezone is a stronger locator than the UI
// locale (an en-US browser in Australia still reports Australia/*), so it is
// preferred. Ambiguous zones (most America/*) are intentionally omitted — those
// fall through to the locale. Australia/* is matched by prefix in
// regionFromTimezone.
var tzRegions = map[string]string{
	"Pacific/Auckland": "NZ", "Pacific/Chatham": "NZ",
	"Europe/London": "GB", "Europe/Dublin": "IE", "Europe/Paris": "FR",
	"Europe/Berlin": "DE", "Europe/Madrid": "ES", "Europe/Rome": "IT",
	"Europe/Amsterdam": "NL", "Europe/Brussels": "BE", "Europe/Zurich": "CH",
	"Europe/Stockholm": "SE", "Europe/Oslo": "NO", "Europe/Copenhagen": "DK",
	"Asia/Singapore": "SG", "Asia/Kolkata": "IN", "Asia/Calcutta": "IN",
	"Asia/Tokyo": "JP", "Asia/Hong_Kong": "HK", "Asia/Dubai": "AE",
	"Asia/Shanghai": "CN", "Asia/Seoul": "KR", "Africa/Johannesburg": "ZA",
}

// regionFromTimezone maps an IANA timezone (navigator-detected, e.g.
// "Australia/Perth") to a region for the common cases. Returns "" for
// unknown/ambiguous zones (including the UTC fallback some browsers report).
func regionFromTimezone(tz string) string {
	tz = strings.TrimSpace(tz)
	if tz == "" {
		return ""
	}
	if strings.HasPrefix(tz, "Australia/") {
		return "AU"
	}
	return tzRegions[tz]
}

// resolveRegion picks the ISO region used to pre-select the phone country
// combobox and to seed E.164 normalization when the visitor has not explicitly
// picked a country. It prefers the timezone region (strongest locator), then the
// browser locale region, validated against the known country list. Returns ""
// when neither is known — the combobox then has no default and normalizePhone
// only handles already-international numbers.
func resolveRegion(locale, timezone string) string {
	for _, r := range []string{regionFromTimezone(timezone), regionFromLocale(locale)} {
		if r != "" {
			if _, ok := countryByCode(r); ok {
				return r
			}
		}
	}
	return ""
}

// countryByCode returns the country with the given ISO alpha-2 code, or false.
func countryByCode(code string) (Country, bool) {
	code = strings.ToUpper(strings.TrimSpace(code))
	for _, c := range countries {
		if c.Code == code {
			return c, true
		}
	}
	return Country{}, false
}

// countryFlag returns the emoji flag for a 2-letter ISO region code by mapping
// each letter to its Unicode regional-indicator symbol. "" for invalid codes.
func countryFlag(code string) string {
	code = strings.ToUpper(strings.TrimSpace(code))
	if len(code) != 2 || !isASCIILetters(code) {
		return ""
	}
	r := []rune(code)
	return string(rune(0x1F1E6+(r[0]-'A'))) + string(rune(0x1F1E6+(r[1]-'A')))
}

// countryLabel renders the human label shown in the combobox and its pre-fill,
// e.g. "🇦🇺 Australia (+61)". Returns "" when the code is unknown.
func countryLabel(code string) string {
	c, ok := countryByCode(code)
	if !ok {
		return ""
	}
	if flag := countryFlag(c.Code); flag != "" {
		return flag + " " + c.Name + " (" + c.Dial + ")"
	}
	return c.Name + " (" + c.Dial + ")"
}
