"""Historical FX lookup for converting foreign funds to IDR.

Uses Frankfurter (https://www.frankfurter.app) — free, no API key, ECB historical
rates. Returns the rate for the requested date (Frankfurter falls back to the most
recent prior business day automatically).
"""
import logging
from decimal import Decimal, InvalidOperation

import requests

logger = logging.getLogger(__name__)

# Process-local cache: {(currency, iso_date): Decimal | None}
_CACHE: dict[tuple[str, str], Decimal | None] = {}


def fetch_idr_rate(currency: str, date) -> Decimal | None:
    """IDR per 1 unit of `currency` on `date` (a date object). None on failure.

    `currency == "IDR"` short-circuits to 1.
    """
    currency = (currency or "").upper()
    if currency == "IDR":
        return Decimal("1")
    if not currency or date is None:
        return None

    iso = date.isoformat()
    key = (currency, iso)
    if key in _CACHE:
        return _CACHE[key]

    url = f"https://api.frankfurter.app/{iso}?from={currency}&to=IDR"
    rate: Decimal | None = None
    try:
        resp = requests.get(url, timeout=6)
        resp.raise_for_status()
        raw = resp.json().get("rates", {}).get("IDR")
        if raw is not None:
            rate = Decimal(str(raw))
    except (requests.RequestException, ValueError, InvalidOperation, KeyError) as exc:
        logger.warning("FX lookup failed for %s on %s: %s", currency, iso, exc)
        rate = None

    _CACHE[key] = rate
    return rate


def convert_between(value, from_ccy, to_ccy, fund=None):
    """Convert `value` from `from_ccy` to `to_ccy` at today's rate, pivoting
    through IDR. Both legs use today's rate for a consistent conversion.

    `fund` is accepted for call-site compatibility but is not used for the rate.
    Returns a Decimal, or None if a needed rate can't be resolved.
    """
    from django.utils import timezone

    from_ccy = (from_ccy or "").upper()
    to_ccy = (to_ccy or "").upper()
    if not from_ccy or not to_ccy or value is None:
        return None
    if from_ccy == to_ccy:
        return Decimal(value)

    today = timezone.now().date()
    from_rate = fetch_idr_rate(from_ccy, today)   # IDR per 1 from_ccy, today
    to_rate = fetch_idr_rate(to_ccy, today)       # IDR per 1 to_ccy, today
    if from_rate is None or to_rate in (None, Decimal("0")):
        return None
    return (Decimal(value) * from_rate) / to_rate


def convert_fund(fund, save=True):
    """Fill fund.exchange_rate + fund.amount_idr. IDR is 1:1; foreign uses the rate
    on received_date (→ agreement_date → today). Returns True if values changed."""
    from django.utils import timezone

    if fund.currency and fund.currency.upper() == "IDR":
        rate = Decimal("1")
    else:
        ref_date = fund.received_date or fund.agreement_date or timezone.now().date()
        rate = fetch_idr_rate(fund.currency, ref_date)

    new_idr = (fund.amount * rate) if rate is not None else None
    if fund.exchange_rate == rate and fund.amount_idr == new_idr:
        return False
    fund.exchange_rate = rate
    fund.amount_idr = new_idr
    if save:
        fund.save(update_fields=["exchange_rate", "amount_idr", "updated_at"])
    return True
