from __future__ import annotations

# code, English name, native name, script or None for Latin.
_ROWS: list[tuple[str, str, str, str | None]] = [
    ("hi", "Hindi", "हिन्दी", "Devanagari"),
    ("en", "English", "English", "Latin"),
    ("ur", "Urdu", "اردو", "Arabic"),
    ("pa", "Punjabi", "ਪੰਜਾਬੀ", "Gurmukhi"),
    ("bn", "Bengali", "বাংলা", "Bengali"),
    ("as", "Assamese", "অসমীয়া", "Bengali"),
    ("ta", "Tamil", "தமிழ்", "Tamil"),
    ("te", "Telugu", "తెలుగు", "Telugu"),
    ("mr", "Marathi", "मराठी", "Devanagari"),
    ("gu", "Gujarati", "ગુજરાતી", "Gujarati"),
    ("kn", "Kannada", "ಕನ್ನಡ", "Kannada"),
    ("ml", "Malayalam", "മലയാളം", "Malayalam"),
    ("or", "Odia", "ଓଡ଼ିଆ", "Odia"),
    ("ne", "Nepali", "नेपाली", "Devanagari"),
    ("sa", "Sanskrit", "संस्कृतम्", "Devanagari"),
    ("es", "Spanish", "Español", "Latin"),
    ("fr", "French", "Français", "Latin"),
    ("de", "German", "Deutsch", "Latin"),
    ("pt", "Portuguese", "Português", "Latin"),
    ("it", "Italian", "Italiano", "Latin"),
    ("nl", "Dutch", "Nederlands", "Latin"),
    ("pl", "Polish", "Polski", "Latin"),
    ("cs", "Czech", "Čeština", "Latin"),
    ("sv", "Swedish", "Svenska", "Latin"),
    ("da", "Danish", "Dansk", "Latin"),
    ("fi", "Finnish", "Suomi", "Latin"),
    ("ro", "Romanian", "Română", "Latin"),
    ("hu", "Hungarian", "Magyar", "Latin"),
    ("el", "Greek", "Ελληνικά", "Greek"),
    ("ru", "Russian", "Русский", "Cyrillic"),
    ("uk", "Ukrainian", "Українська", "Cyrillic"),
    ("tr", "Turkish", "Türkçe", "Latin"),
    ("ar", "Arabic", "العربية", "Arabic"),
    ("fa", "Persian", "فارسی", "Arabic"),
    ("he", "Hebrew", "עברית", "Hebrew"),
    ("id", "Indonesian", "Bahasa Indonesia", "Latin"),
    ("ms", "Malay", "Bahasa Melayu", "Latin"),
    ("vi", "Vietnamese", "Tiếng Việt", "Latin"),
    ("th", "Thai", "ไทย", "Thai"),
    ("ja", "Japanese", "日本語", "Japanese"),
    ("ko", "Korean", "한국어", "Hangul"),
    ("zh", "Chinese", "中文", "Chinese"),
    ("sw", "Swahili", "Kiswahili", "Latin"),
]

BY_CODE: dict[str, dict[str, str | None]] = {
    code: {"code": code, "name": name, "native": native, "script": script}
    for code, name, native, script in _ROWS
}

SOUTH_ASIAN = {"hi", "ur", "pa", "bn", "as", "ta", "te", "mr", "gu", "kn", "ml", "or", "ne", "sa"}

_RANGES: dict[str, tuple[str, str]] = {
    "Devanagari": ("\u0900", "\u097F"),
    "Bengali": ("\u0980", "\u09FF"),
    "Gurmukhi": ("\u0A00", "\u0A7F"),
    "Gujarati": ("\u0A80", "\u0AFF"),
    "Odia": ("\u0B00", "\u0B7F"),
    "Tamil": ("\u0B80", "\u0BFF"),
    "Telugu": ("\u0C00", "\u0C7F"),
    "Kannada": ("\u0C80", "\u0CFF"),
    "Malayalam": ("\u0D00", "\u0D7F"),
    "Arabic": ("\u0600", "\u06FF"),
    "Cyrillic": ("\u0400", "\u04FF"),
    "Hebrew": ("\u0590", "\u05FF"),
    "Greek": ("\u0370", "\u03FF"),
    "Thai": ("\u0E00", "\u0E7F"),
    "Hangul": ("\uAC00", "\uD7AF"),
    "Chinese": ("\u4E00", "\u9FFF"),
}

# A short prompt keeps Hindi in Devanagari and lets spoken English stay in English.
# It is dropped if the model repeats it.
PROMPTS = {
    "hi": "यह हिंदी में कही गई बात है। English शब्द English में लिखें, जैसे sales, marketing, product, team, deal.",
}


def public_list() -> list[dict[str, str | None]]:
    items = []
    for code, _name, _native, _script in _ROWS:
        item = dict(BY_CODE[code])
        if code in {"hi", "en"}:
            item["group"] = "primary"
        elif code in SOUTH_ASIAN:
            item["group"] = "south"
        else:
            item["group"] = "more"
        items.append(item)
    return items


def is_known(code: str) -> bool:
    return code == "auto" or code in BY_CODE


def display_name(code: str | None) -> str:
    if not code or code == "auto":
        return "the spoken language"
    item = BY_CODE.get(code)
    return item["name"] if item and item["name"] else code


def script_name(code: str | None) -> str | None:
    if not code:
        return None
    item = BY_CODE.get(code)
    if not item:
        return None
    return item["script"]


def _in_script(char: str, script: str) -> bool:
    if script == "Latin":
        return char.isascii() and char.isalpha()
    if script == "Japanese":
        return ("\u3040" <= char <= "\u30ff") or ("\u4e00" <= char <= "\u9fff")
    bounds = _RANGES.get(script)
    if not bounds:
        return False
    return bounds[0] <= char <= bounds[1]


def script_warning(code: str | None, text: str) -> str | None:
    if not code or code == "auto" or not text.strip():
        return None
    item = BY_CODE.get(code)
    if not item or not item["script"]:
        return None
    letters = [char for char in text if char.isalpha()]
    if len(letters) < 12:
        return None
    if code == "hi":
        devanagari = sum(1 for char in letters if _in_script(char, "Devanagari"))
        latin = sum(1 for char in letters if _in_script(char, "Latin"))
        if devanagari / len(letters) >= 0.35 and (devanagari + latin) / len(letters) >= 0.85:
            return None
    hits = sum(1 for char in letters if _in_script(char, str(item["script"])))
    ratio = hits / len(letters)
    if ratio >= 0.6:
        return None
    if item["script"] == "Latin":
        return f"Most of this transcript does not look like {item['name']}."
    return (
        f"Most of this transcript is not in {item['script']}. "
        f"Set the language to {item['name']} and, for a real check, use the medium speech model."
    )
