"""Derive a medicine's composition (salt/generic name) from its rxItemId.

Amazon encodes the active ingredients of a medicine directly inside the
``rxItemId``, so the connector can produce the composition string sent to 1Rx
without any external catalog lookup. See
``scripts/TMP_rxItemID_Reference_Guide.docx`` for the authoritative format.

rxItemId layout (top level, single underscore separated)::

    BRAND _ ACTIVE_INGREDIENTS _ DOSAGE_FORM

The brand is the first segment and the dosage form is the last segment, and
neither contains an underscore. Strength unit tokens DO contain underscores
(e.g. ``PERCENT_WEIGHT_BY_WEIGHT``), so the active-ingredients section is
isolated by peeling off the first and last segments rather than splitting on
every underscore.

Active-ingredients section: one or more ingredient blocks separated by ``__``
(double underscore). Each block is ``#``-delimited::

    NAME # STRENGTH_VALUE # STRENGTH_UNIT # BASIS_VALUE # BASIS_UNIT # ING_ID

Only the primary strength (1st numeric) is used; the optional basis strength is
for internal catalog matching and is ignored. ``%20`` in a name decodes to a
space.

Output format (what 1Rx expects)::

    NAME-VALUEUNIT+NAME-VALUEUNIT+...

i.e. UPPERCASE ingredient name, a hyphen, the strength value with its unit
abbreviation appended (no space), ingredients joined by ``+`` (no spaces).

Examples::

    ANOSUM_LIDOCAINE#4.0#PERCENT_WEIGHT_BY_WEIGHT###1__METRONIDAZOLE#1.0#PERCENT_WEIGHT_BY_WEIGHT###2__SUCRALFATE#7.0#PERCENT_WEIGHT_BY_WEIGHT###3_CREAM
        -> "LIDOCAINE-4%W/W+METRONIDAZOLE-1%W/W+SUCRALFATE-7%W/W"
    CILIDIN_CILNIDIPINE#10.0#MILLIGRAMS###1__TELMISARTAN#40.0#MILLIGRAMS###2_TABLETS
        -> "CILNIDIPINE-10MG+TELMISARTAN-40MG"
    IVREA_IVERMECTIN%20IP#0.5#PERCENT_WEIGHT_BY_VOLUME###1_SHAMPOO
        -> "IVERMECTIN IP-0.5%W/V"
"""

# Strength unit token -> abbreviation appended to the strength value. Unknown
# units fall through to their raw token.
UNIT_ABBREVIATIONS = {
    "MILLIGRAMS": "MG",
    "MICROGRAMS": "MCG",
    "GRAMS": "GM",
    "PERCENT_WEIGHT_BY_VOLUME": "%W/V",
    "PERCENT_WEIGHT_BY_WEIGHT": "%W/W",
    "INTERNATIONAL_UNITS": "IU",
    "MILLILITERS": "ML",
}


def composition_from_rxitem(rx_item_id: str) -> str:
    """Return the printable composition for an rxItemId, or "" if it can't be
    decoded (missing/blank id, no active-ingredients section, or no parseable
    ingredient blocks). Never raises — an undecodable id yields ""."""
    try:
        return _parse(rx_item_id)
    except Exception:
        return ""


def _parse(rx_item_id: str) -> str:
    if not rx_item_id or "_" not in rx_item_id:
        return ""

    # Peel off BRAND (first segment) and DOSAGE_FORM (last segment); whatever
    # remains in between is the active-ingredients section.
    _, rest = rx_item_id.split("_", 1)
    if "_" not in rest:
        # Only two segments (BRAND_DOSAGE) -> no active-ingredients section.
        return ""
    active_section = rest.rsplit("_", 1)[0]

    ingredients = []
    for block in active_section.split("__"):
        rendered = _render_ingredient(block)
        if rendered:
            ingredients.append(rendered)

    return "+".join(ingredients)


def _render_ingredient(block: str) -> str:
    fields = block.split("#")
    name = _format_name(fields[0]) if fields else ""
    if not name:
        return ""

    value = _format_number(fields[1]) if len(fields) > 1 else ""
    unit = fields[2].strip() if len(fields) > 2 else ""

    strength = _format_strength(value, unit)
    return f"{name}-{strength}" if strength else name


def _format_strength(value: str, unit: str) -> str:
    """Append the unit abbreviation directly to the strength value (no space):
    4 + PERCENT_WEIGHT_BY_WEIGHT -> "4%W/W", 500 + MILLIGRAMS -> "500MG"."""
    if not value:
        return ""
    if not unit:
        return value
    return f"{value}{UNIT_ABBREVIATIONS.get(unit, unit)}"


def _format_number(value: str) -> str:
    """Trim trailing zeros from a decimal strength: 4.0 -> 4, 0.50 -> 0.5,
    148.75 -> 148.75. Non-numeric values are returned stripped, as-is."""
    value = (value or "").strip()
    if "." in value:
        value = value.rstrip("0").rstrip(".")
    return value


def _format_name(raw: str) -> str:
    """Decode %20 to spaces, collapse whitespace, and uppercase the ingredient
    name to match the format 1Rx expects."""
    name = (raw or "").replace("%20", " ")
    return " ".join(name.split()).upper()
