from decimal import Decimal, ROUND_HALF_UP
from datetime import date

UNITS = (
    "ZERO ONE TWO THREE FOUR FIVE SIX SEVEN EIGHT NINE TEN ELEVEN TWELVE "
    "THIRTEEN FOURTEEN FIFTEEN SIXTEEN SEVENTEEN EIGHTEEN NINETEEN"
).split()

TENS = "ZERO TEN TWENTY THIRTY FORTY FIFTY SIXTY SEVENTY EIGHTY NINETY".split()

def format_date_en(d):
    if not d:
        return ''

    day = d.day

    # Gestion des suffixes ordinaux
    if 10 <= day % 100 <= 20:
        suffix = 'TH'
    else:
        suffix = {1: 'ST', 2: 'ND', 3: 'RD'}.get(day % 10, 'TH')

    return f"{day}{suffix} {d.strftime('%B').upper()} {d.year}"

def _under_thousand(n):
    words = []

    hundreds = n // 100
    remainder = n % 100

    if hundreds:
        words.append(UNITS[hundreds])
        words.append("HUNDRED")
        if remainder:
            words.append("AND")

    if remainder:
        if remainder < 20:
            words.append(UNITS[remainder])
        else:
            words.append(TENS[remainder // 10])
            if remainder % 10:
                words.append(UNITS[remainder % 10])

    return " ".join(words)


def integer_to_words(n):
    if n == 0:
        return "ZERO"

    parts = []

    millions = n // 1_000_000
    thousands = (n // 1_000) % 1_000
    remainder = n % 1_000

    if millions:
        parts.append(_under_thousand(millions))
        parts.append("MILLION")

    if thousands:
        parts.append(_under_thousand(thousands))
        parts.append("THOUSAND")

    if remainder:
        parts.append(_under_thousand(remainder))

    return " ".join(parts)


# ==============================
# 💰 MONETARY
# ==============================

def amount_to_currency_words(amount,
                             major_singular="DOLLAR",
                             major_plural="DOLLARS",
                             minor_singular="CENT",
                             minor_plural="CENTS"):
    """
    Example:
    1.20 → ONE DOLLAR AND TWENTY CENTS
    2.00 → TWO DOLLARS
    """

    amount = Decimal(str(amount)).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)

    integer_part = int(amount)
    decimal_part = int((amount - integer_part) * 100)

    words = []

    # Major unit
    major_words = integer_to_words(integer_part)
    words.append(major_words)

    if integer_part == 1:
        words.append(major_singular)
    else:
        words.append(major_plural)

    # Minor unit
    if decimal_part:
        words.append("AND")
        minor_words = integer_to_words(decimal_part)
        words.append(minor_words)

        if decimal_part == 1:
            words.append(minor_singular)
        else:
            words.append(minor_plural)

    return " ".join(words)


# ==============================
# ⚖️ QUANTITY WITH UNIT
# ==============================

def quantity_to_words(quantity,
                      unit_singular="METRIC TON",
                      unit_plural="METRIC TONS"):
    """
    Example:
    1 → ONE METRIC TON
    23 → TWENTY THREE METRIC TONS
    1.5 → ONE POINT FIVE METRIC TONS
    """

    quantity = Decimal(str(quantity)).normalize()

    if quantity == quantity.to_integral():
        integer_part = int(quantity)
        words = integer_to_words(integer_part)

        if integer_part == 1:
            unit = unit_singular
        else:
            unit = unit_plural

        return f"{words} {unit}"

    else:
        # lecture décimale simple pour quantités
        integer_part = int(quantity)
        decimal_str = str(quantity).split(".")[1]

        words = integer_to_words(integer_part)
        decimal_words = " ".join(UNITS[int(d)] for d in decimal_str)

        return f"{words} POINT {decimal_words} {unit_plural}"