"""LLM 调用成本计算(纯逻辑,无 DB):按 model 分桶累加 token × 单价,返回总成本(元)+ 价格快照。

用量取自 comparison_record.llm_calls[].usage(pricebot 已归一为 prompt/completion_tokens);
error / 无 usage 的调用跳过。price_cfg = {per_model:{model:{input_per_1m,output_per_1m}}, default:{...}}。
成本单位「元」——单次亚分级,用 float(不用 *_cents);snapshot 只含本次用到的模型的价(审计用,
不存整张价表)。用到但没配价(既无 per_model 又无 default)的模型 → 快照标 unpriced,成本按 0 计。
"""
from __future__ import annotations

_PRICE_KEY = "llm_token_price"


def get_llm_prices(db) -> dict:
    """读 LLM 单价配置(app_config;表内无则回退 CONFIG_DEFS 默认)。返回 compute_llm_cost 的 price_cfg。"""
    from app.repositories import app_config  # 延迟 import:compute_llm_cost 纯逻辑不牵连 DB 层
    return app_config.get_value(db, _PRICE_KEY)


def compute_llm_cost(calls: list[dict], price_cfg: dict) -> tuple[float | None, dict | None]:
    """遍历 calls 按 model 分桶,cost = Σ(入/1e6*入价 + 出/1e6*出价);无有效调用 → (None, None)。"""
    if not calls:
        return None, None
    per_model = price_cfg.get("per_model") or {}
    default = price_cfg.get("default")
    buckets: dict[str, list[int]] = {}  # model -> [Σprompt_tokens, Σcompletion_tokens]
    for c in calls:
        if c.get("error"):
            continue
        usage = c.get("usage") or {}
        model = c.get("model") or "unknown"
        b = buckets.setdefault(model, [0, 0])
        b[0] += usage.get("prompt_tokens") or 0
        b[1] += usage.get("completion_tokens") or 0
    if not buckets:  # 全是 error / 无 usage
        return None, None
    total = 0.0
    prices: dict[str, dict] = {}
    for model, (tin, tout) in buckets.items():
        price = per_model.get(model, default)
        in_p = price.get("input_per_1m") if isinstance(price, dict) else None
        out_p = price.get("output_per_1m") if isinstance(price, dict) else None
        # 没配价 / 无 default / 单价残缺或非法(配置页手改 JSON 可能存出脏数据)→ 标记待补价、
        # 不计入成本;绝不抛异常,以免连累同一回填里的 token/llm_calls 落库。
        if not isinstance(in_p, (int, float)) or not isinstance(out_p, (int, float)):
            prices[model] = {"input_per_1m": in_p, "output_per_1m": out_p, "unpriced": True}
            continue
        total += tin / 1e6 * in_p + tout / 1e6 * out_p
        prices[model] = {
            "input_per_1m": in_p,
            "output_per_1m": out_p,
            "_source": "per_model" if model in per_model else "default",
        }
    return round(total, 6), {"mode": "per_model", "prices": prices}
