"""Azerbaijani formatter for the `in_words` / `base_in_words` fields.

Frappe's `money_in_words()` produces output like
    "AZN Dörd Min Doqquz Yüz Beş yalnız."
which is grammatically correct gettext but not what Azerbaijani accounting
documents actually look like. Native convention is:

    "Dörd min doqquz yüz beş manat 52 qəpik"

This hook re-formats the field after Frappe's `set_total_in_words` has run.
Triggered as a `validate` doc_event from hooks.py for every doctype that
carries `in_words` / `base_in_words`. Activates only when `frappe.local.lang
== "az"` — other languages keep Frappe's default output.
"""

from __future__ import annotations

import frappe
from num2words import num2words


# Currency code → (main name, fraction name). Add languages as needed.
# Fraction name "" disables the fraction-unit suffix (just shows digits).
CURRENCY_NAMES_AZ: dict[str, tuple[str, str]] = {
    "AZN": ("manat", "qəpik"),
    "USD": ("dollar", "sent"),
    "EUR": ("avro", "sent"),
    "RUB": ("rubl", "qəpik"),
    "TRY": ("lirə", "quruş"),
    "GBP": ("funt sterlinq", "pens"),
}


def format_in_words_az(doc, method=None):
    """Overwrite doc.in_words / doc.base_in_words with native AZ format.

    Hooked as a `validate` doc_event. Runs *after* the controller's own
    validate() — which is where Frappe's `set_total_in_words` lives — so
    the fields are already populated by the time we get here. We just
    replace them.
    """
    if frappe.local.lang != "az":
        return

    meta = doc.meta

    if meta.get_field("in_words"):
        amount = abs(_resolve_total(doc, base=False))
        currency = _resolve_currency(doc, base=False)
        doc.in_words = _format(amount, currency)

    if meta.get_field("base_in_words"):
        amount = abs(_resolve_total(doc, base=True))
        currency = _resolve_currency(doc, base=True)
        doc.base_in_words = _format(amount, currency)


def _resolve_total(doc, base: bool) -> float:
    """Return the amount to convert to words.

    Always uses `grand_total` (not `rounded_total`) because Azerbaijani
    documents show exact "X manat Y qəpik" — never rounded to whole manat.
    Frappe's default flips to `rounded_total` when "Rounded Total" is enabled
    on the Currency, which drops the fraction; we don't want that here.
    """
    prefix = "base_" if base else ""

    if doc.doctype == "Payment Entry":
        if doc.get("payment_type") == "Receive":
            return float(doc.get(f"{prefix}received_amount") or 0)
        return float(doc.get(f"{prefix}paid_amount") or 0)

    return float(doc.get(f"{prefix}grand_total") or 0)


def _resolve_currency(doc, base: bool) -> str:
    if base:
        # company_currency is a @property on AccountsController (lazy-loaded
        # from erpnext.get_company_currency), not a stored field. .get() would
        # miss it; getattr triggers the descriptor.
        return getattr(doc, "company_currency", None) or doc.get("company_currency") or ""
    if doc.doctype == "Payment Entry":
        if doc.get("payment_type") == "Receive":
            return doc.get("paid_to_account_currency") or ""
        return doc.get("paid_from_account_currency") or ""
    return doc.get("currency") or ""


def _format(amount: float, currency: str) -> str:
    """Produce 'Dörd min doqquz yüz beş manat 52 qəpik' style string.

    Edge cases:
      - amount == 0 → empty string (matches Frappe behaviour, field stays blank)
      - main == 0, fraction != 0 → 'Sıfır manat 52 qəpik'
      - fraction == 0 → suffix omitted: 'Dörd min doqquz yüz manat'
      - unknown currency → ISO code used as-is, no fraction unit name
    """
    if not amount:
        return ""

    main = int(amount)
    fraction = round((float(amount) - main) * 100)

    currency_word, fraction_word = CURRENCY_NAMES_AZ.get(
        (currency or "").upper(),
        ((currency or "").lower(), ""),
    )

    if main:
        words = num2words(main, lang="az").capitalize()
    else:
        words = "Sıfır"

    out = f"{words} {currency_word}".rstrip()

    if fraction:
        if fraction_word:
            out += f" {fraction} {fraction_word}"
        else:
            out += f" {fraction}"

    return out
