from __future__ import annotations

from decimal import Decimal, InvalidOperation
from typing import Any

from .storage import Storage


def record_order_fills(storage: Storage, symbol: str, order_payload: dict[str, Any]) -> int:
    fills = order_payload.get("fills")
    if not isinstance(fills, list):
        return 0

    inserted = 0
    valid_fills = [fill for fill in fills if isinstance(fill, dict)]
    total_quantity = _total_fill_quantity(valid_fills)
    for fill in valid_fills:
        trade = _trade_from_order_fill(symbol, order_payload, fill, total_quantity=total_quantity, fill_count=len(valid_fills))
        if trade is None:
            continue
        if storage.record_spot_trade_fill(symbol, trade):
            inserted += 1
    return inserted


def _trade_from_order_fill(
    symbol: str,
    order_payload: dict[str, Any],
    fill: dict[str, Any],
    *,
    total_quantity: Decimal | None,
    fill_count: int,
) -> dict[str, Any] | None:
    side = str(order_payload.get("side", "")).upper()
    if side not in {"BUY", "SELL"}:
        return None
    try:
        trade_id = int(fill["tradeId"])
        order_id = int(order_payload["orderId"])
        price = Decimal(str(fill["price"]))
        quantity = Decimal(str(fill["qty"]))
        commission = Decimal(str(fill["commission"]))
        created_at_ms = int(order_payload["transactTime"])
    except (KeyError, TypeError, ValueError, InvalidOperation):
        return None
    if not all(value.is_finite() for value in (price, quantity, commission)):
        return None
    if price <= 0 or quantity <= 0 or commission < 0:
        return None

    order_list_id = order_payload.get("orderListId")
    quote_quantity = _fill_quote_quantity(order_payload, price, quantity, total_quantity, fill_count)
    return {
        "id": trade_id,
        "orderId": order_id,
        "orderListId": order_list_id,
        "price": str(fill["price"]),
        "qty": str(fill["qty"]),
        "quoteQty": quote_quantity,
        "commission": str(fill["commission"]),
        "commissionAsset": str(fill["commissionAsset"]).upper(),
        "time": created_at_ms,
        "isBuyer": side == "BUY",
        "isMaker": bool(fill.get("isMaker", False)),
        "isBestMatch": bool(fill.get("isBestMatch", True)),
    }


def _total_fill_quantity(fills: list[dict[str, Any]]) -> Decimal | None:
    total = Decimal("0")
    for fill in fills:
        try:
            quantity = Decimal(str(fill["qty"]))
        except (KeyError, InvalidOperation, ValueError):
            return None
        if not quantity.is_finite() or quantity <= 0:
            return None
        total += quantity
    return total if total > 0 else None


def _fill_quote_quantity(
    order_payload: dict[str, Any],
    price: Decimal,
    quantity: Decimal,
    total_quantity: Decimal | None,
    fill_count: int,
) -> str:
    raw_cumulative_quote = order_payload.get("cummulativeQuoteQty")
    if raw_cumulative_quote is not None and total_quantity is not None:
        try:
            cumulative_quote = Decimal(str(raw_cumulative_quote))
        except (InvalidOperation, ValueError):
            cumulative_quote = None
        if cumulative_quote is not None and cumulative_quote.is_finite() and cumulative_quote >= 0:
            if fill_count == 1:
                return str(raw_cumulative_quote)
            return str(cumulative_quote * (quantity / total_quantity))
    return str(price * quantity)
