from __future__ import annotations

import re
from typing import Literal, Tuple

Mode = Literal["digits", "words"]

_KHMER_DIGITS = str.maketrans(
    {"0": "០", "1": "១", "2": "២", "3": "៣", "4": "៤", "5": "៥", "6": "៦", "7": "៧", "8": "៨", "9": "៩"}
)

_UNITS = {
    0: "សូន្យ",
    1: "មួយ",
    2: "ពីរ",
    3: "បី",
    4: "បួន",
    5: "ប្រាំ",
    6: "ប្រាំមួយ",
    7: "ប្រាំពីរ",
    8: "ប្រាំបី",
    9: "ប្រាំបួន",
}

_TENS = {10: "ដប់", 20: "ម្ភៃ", 30: "សាមសិប", 40: "សែសិប", 50: "ហាសិប"}

_TIME_RE = re.compile(r"^\s*(\d{1,2})\s*:\s*(\d{2})\s*(AM|PM)?\s*$", re.IGNORECASE)


def _number_to_khmer_words(n: int) -> str:
    if n < 0 or n > 59:
        raise ValueError("number out of supported range (0-59)")
    if n < 10:
        return _UNITS[n]
    if n < 20:
        if n == 10:
            return _TENS[10]
        return _TENS[10] + _UNITS[n - 10]
    tens = (n // 10) * 10
    ones = n % 10
    if ones == 0:
        return _TENS[tens]
    return _TENS[tens] + _UNITS[ones]


def _number_to_khmer_digits(n: int) -> str:
    return str(n).translate(_KHMER_DIGITS)


def _period_km(hour24: int) -> str:
    if 0 <= hour24 <= 5:
        return "យប់"
    if 6 <= hour24 <= 11:
        return "ព្រឹក"
    if 12 <= hour24 <= 17:
        return "រសៀល"
    return "ល្ងាច"


def _to_12h(hour24: int) -> int:
    h = hour24 % 12
    return 12 if h == 0 else h


def _parse_time(time_str: str) -> Tuple[int, int]:
    m = _TIME_RE.match(time_str)
    if not m:
        raise ValueError("Invalid time format. Use 'H:MM', 'HH:MM', or 'H:MM AM/PM'.")
    hour = int(m.group(1))
    minute = int(m.group(2))
    ampm = m.group(3)
    if minute < 0 or minute > 59:
        raise ValueError("Minute must be 00-59.")
    if ampm:
        if hour < 1 or hour > 12:
            raise ValueError("Hour must be 1-12 when using AM/PM.")
        ap = ampm.upper()
        if ap == "AM":
            hour24 = 0 if hour == 12 else hour
        else:
            hour24 = 12 if hour == 12 else hour + 12
    else:
        if hour < 0 or hour > 23:
            raise ValueError("Hour must be 0-23 for 24-hour input.")
        hour24 = hour
    return hour24, minute


def format_time(time_str: str, mode: Mode = "digits") -> str:
    hour24, minute = _parse_time(time_str)
    hour12 = _to_12h(hour24)
    period = _period_km(hour24)

    if mode == "digits":
        h = _number_to_khmer_digits(hour12)
        m = _number_to_khmer_digits(minute)
        return f"ម៉ោង{h} និង {m} នាទី {period}"

    if mode == "words":
        h = _number_to_khmer_words(hour12)
        m = _number_to_khmer_words(minute)
        return f"ម៉ោង{h} និង {m} នាទី {period}"

    raise ValueError("mode must be 'digits' or 'words'")
