"""
Ledger - 黑匣子回放器
append_ledger_event: 追加事件到分类账
replay_trace: 根据 trace_id / intent_id / signal_id 回放完整链路
"""
import json
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Dict, Optional, List


def append_ledger_event(path: Path, category: str, payload: Dict[str, Any]) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    event = {
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "category": category,
        "payload": payload,
    }
    with path.open("a", encoding="utf-8") as f:
        f.write(json.dumps(event, ensure_ascii=False) + "\n")


def _extract_ids(event: dict) -> dict:
    """从事件payload中提取所有可追踪的ID"""
    p = event.get("payload", {})
    signal = p.get("signal", {})
    execution_report = p.get("execution_report", {})

    ids = {
        "signal_id": signal.get("signal_id"),
        "intent_id": signal.get("intent_id") or execution_report.get("intent_id"),
        "trace_id": signal.get("trace_id"),
    }
    return {k: v for k, v in ids.items() if v}


def _match_event(event: dict, key: str, value: str) -> bool:
    """检查事件是否匹配指定的 key=value"""
    ids = _extract_ids(event)
    return ids.get(key) == value


def replay_trace(
    ledger_path: Path,
    trace_id: str = None,
    signal_id: str = None,
    intent_id: str = None,
    limit: int = 100,
) -> List[dict]:
    """
    根据 trace_id / signal_id / intent_id 回放完整链路事件

    参数：
        ledger_path: 日账本文件路径（decision_ledger.ndjson）
        trace_id:   追溯信号层trace_id
        signal_id:  追溯信号ID
        intent_id:  追溯订单intent_id
        limit:     最多返回事件数（默认100）

    返回：
        List[dict]: 按时间排序的事件列表
        每个事件包含：{timestamp, category, payload, matched_id}

    示例：
        events = replay_trace(Path("logs/decision_ledger.ndjson"), signal_id="sig_12345")
        for ev in events:
            print(ev["timestamp"], ev["category"], ev["payload"].get("signal", {}).get("action"))
    """
    if not ledger_path.exists():
        return []

    # 确定匹配键
    match_key, match_value = None, None
    if intent_id:
        match_key, match_value = "intent_id", intent_id
    elif signal_id:
        match_key, match_value = "signal_id", signal_id
    elif trace_id:
        match_key, match_value = "trace_id", trace_id
    else:
        raise ValueError("至少需要提供 trace_id / signal_id / intent_id 之一")

    matched: List[dict] = []
    try:
        for line in ledger_path.read_text(encoding="utf-8").splitlines():
            if not line.strip():
                continue
            try:
                event = json.loads(line)
            except Exception:
                continue

            if _match_event(event, match_key, match_value):
                ids = _extract_ids(event)
                matched.append({
                    "timestamp": event.get("timestamp"),
                    "category": event.get("category"),
                    "payload": event.get("payload"),
                    "matched_id": {k: v for k, v in ids.items() if v},
                })
                if len(matched) >= limit:
                    break
    except Exception:
        pass

    # 按时间戳升序排列
    matched.sort(key=lambda x: x.get("timestamp", ""))
    return matched


def summarize_trace(events: List[dict]) -> dict:
    """
    对回放的事件列表生成摘要
    """
    if not events:
        return {"status": "NO_EVENTS", "count": 0}

    categories = [e.get("category") for e in events]
    first = events[0]
    last = events[-1]

    signal = first.get("payload", {}).get("signal", {})
    execution_report = last.get("payload", {}).get("execution_report", {})

    return {
        "status": "COMPLETE" if len(events) > 1 else "PARTIAL",
        "event_count": len(events),
        "categories": categories,
        "first_ts": first.get("timestamp"),
        "last_ts": last.get("timestamp"),
        "signal_id": signal.get("signal_id"),
        "intent_id": signal.get("intent_id") or execution_report.get("intent_id"),
        "signal_action": signal.get("action"),
        "signal_confidence": signal.get("trace", {}).get("confidence"),
        "governor_status": signal.get("governor_status"),
        "final_execution_status": execution_report.get("status"),
        "final_execution_reason": execution_report.get("reason"),
        "latency_ms": execution_report.get("latency_ms"),
    }

