"""账户流水:交易所原始记录 → 统一行模型."""
from __future__ import annotations

from typing import Any, Optional


ACCOUNT_FUNDING = "funding"
ACCOUNT_TRADING = "trading"
VALID_ACCOUNTS = frozenset({ACCOUNT_FUNDING, ACCOUNT_TRADING})

PAGE_SIZE = 10


def _safe_float(v: Any) -> Optional[float]:
    if v is None or v == "":
        return None
    try:
        return float(v)
    except (TypeError, ValueError):
        return None


def _safe_int(v: Any) -> Optional[int]:
    if v is None or v == "":
        return None
    try:
        n = float(v)
        if n > 1e12:
            return int(n)
        if n > 1e9:
            return int(n)
        return int(n)
    except (TypeError, ValueError):
        return None


def _ts_ms(v: Any) -> Optional[int]:
    if v is None or v == "":
        return None
    try:
        n = float(v)
    except (TypeError, ValueError):
        return None
    if n > 1e12:
        return int(n)
    if n > 1e10:
        return int(n)
    return int(n * 1000.0)


def kind_from_raw(raw_type: str, amount: Optional[float] = None) -> str:
    t = (raw_type or "").strip().lower()
    if not t:
        return "other"
    if "deposit" in t or t in ("1", "funding_deposit"):
        return "deposit"
    if "withdraw" in t or "withdrawal" in t:
        return "withdraw"
    if "transfer" in t or "dnw" in t or t in ("2", "18", "19"):
        if amount is not None and amount < 0:
            return "transfer_out"
        if amount is not None and amount > 0:
            return "transfer_in"
        return "transfer"
    if "funding" in t and "fee" in t:
        return "funding_fee"
    if t in ("funding_fee", "fundingfee", "8"):
        return "funding_fee"
    if "commission" in t or "fee" in t or t in ("commission", "5", "fee"):
        return "commission"
    if "realiz" in t or "pnl" in t or t in ("realized_pnl", "realizedpnl", "3"):
        return "realized_pnl"
    if "liqui" in t:
        return "liquidate"
    return "other"


def kind_label_zh(kind: str) -> str:
    return {
        "deposit": "充值",
        "withdraw": "提现",
        "transfer": "划转",
        "transfer_in": "划入",
        "transfer_out": "划出",
        "realized_pnl": "已实现盈亏",
        "funding_fee": "资金费",
        "commission": "手续费",
        "liquidate": "强平",
        "other": "其他",
    }.get((kind or "").strip().lower(), "其他")


def make_ref_id(*parts: Any) -> str:
    bits = []
    for p in parts:
        if p is None:
            continue
        s = str(p).strip()
        if s:
            bits.append(s)
    return "|".join(bits) if bits else ""


def normalize_row(
    *,
    account: str,
    ccy: str,
    amount: Any,
    ts_ms: Any,
    ref_id: str,
    raw_type: str = "",
    balance_after: Any = None,
    symbol: str = "",
    note: str = "",
    kind: str = "",
) -> Optional[dict[str, Any]]:
    acc = (account or "").strip().lower()
    if acc not in VALID_ACCOUNTS:
        return None
    ccy_u = (ccy or "").strip().upper()
    if not ccy_u:
        return None
    amt = _safe_float(amount)
    if amt is None:
        return None
    ts = _ts_ms(ts_ms)
    if ts is None or ts <= 0:
        return None
    rid = (ref_id or "").strip() or make_ref_id(acc, ccy_u, ts, amt, raw_type)
    k = (kind or "").strip().lower() or kind_from_raw(raw_type, amt)
    bal = _safe_float(balance_after)
    return {
        "account": acc,
        "ccy": ccy_u,
        "amount": amt,
        "balance_after": bal,
        "kind": k,
        "kind_label": kind_label_zh(k),
        "raw_type": (raw_type or "").strip()[:120],
        "symbol": (symbol or "").strip()[:80],
        "ref_id": rid[:200],
        "ts_ms": int(ts),
        "note": (note or "").strip()[:240],
    }


def from_ccxt_ledger_entry(entry: dict[str, Any], *, account: str) -> Optional[dict[str, Any]]:
    if not isinstance(entry, dict):
        return None
    info = entry.get("info") if isinstance(entry.get("info"), dict) else {}
    amount = entry.get("amount")
    if amount is None:
        amount = entry.get("change")
    if amount is None:
        amount = info.get("balChg") or info.get("change") or info.get("income") or info.get("amount")
    ts = entry.get("timestamp") or entry.get("datetime")
    if ts is None:
        ts = info.get("time") or info.get("uTime") or info.get("ts") or info.get("create_time") or info.get("createDate")
    ccy = entry.get("currency") or info.get("ccy") or info.get("asset") or info.get("currency") or "USDT"
    raw_type = (
        entry.get("type")
        or entry.get("status")
        or info.get("type")
        or info.get("incomeType")
        or info.get("change_type")
        or info.get("subType")
        or ""
    )
    if isinstance(raw_type, (int, float)):
        raw_type = str(raw_type)
    balance_after = entry.get("balance") or info.get("bal") or info.get("balance")
    symbol = entry.get("symbol") or info.get("instId") or info.get("symbol") or info.get("contract") or ""
    ref = (
        entry.get("id")
        or info.get("billId")
        or info.get("tranId")
        or info.get("id")
        or info.get("trade_id")
        or ""
    )
    note = entry.get("description") or info.get("info") or info.get("text") or ""
    return normalize_row(
        account=account,
        ccy=str(ccy),
        amount=amount,
        ts_ms=ts,
        ref_id=str(ref) if ref != "" else make_ref_id(account, ccy, ts, amount, raw_type),
        raw_type=str(raw_type),
        balance_after=balance_after,
        symbol=str(symbol or ""),
        note=str(note or ""),
    )
