#!/usr/bin/env python3
"""
Export OpenClaw incumbent replay JSONL from existing AWOOOI audit tables.

This script is read-only: it queries agent_sessions, auto_repair_executions, and
incident_evidence, then writes candidate_id=openclaw_incumbent records that can
be scored by scripts/ai-agent-replay-scorecard.py.
"""

from __future__ import annotations

import argparse
import asyncio
import json
import sys
from datetime import timedelta
from pathlib import Path

from sqlalchemy import and_, func, select


ROOT = Path(__file__).resolve().parents[1]
API_SRC = ROOT / "apps" / "api"
sys.path.insert(0, str(API_SRC))

from src.db.base import get_db_context  # noqa: E402
from src.db.models import AgentSession, AutoRepairExecution, IncidentEvidence  # noqa: E402
from src.services.agent_replacement_evaluator import (  # noqa: E402
    build_openclaw_incumbent_record,
)
from src.utils.timezone import now_taipei  # noqa: E402


async def main_async() -> int:
    parser = argparse.ArgumentParser(
        description="Export OpenClaw incumbent replay JSONL from DB."
    )
    parser.add_argument("--output", required=True, help="Output JSONL path")
    parser.add_argument("--limit", type=int, default=100, help="Max incidents")
    parser.add_argument("--days", type=int, default=30, help="Lookback days")
    parser.add_argument(
        "--run-id",
        default=f"openclaw-incumbent-{now_taipei().strftime('%Y%m%d%H%M%S')}",
        help="Replay run id",
    )
    args = parser.parse_args()

    cutoff = now_taipei() - timedelta(days=args.days)
    records = []
    try:
        async with get_db_context() as db:
            incident_ids = await _incident_ids(db, cutoff=cutoff, limit=args.limit)
            for incident_id in incident_ids:
                coordinator = await _latest_coordinator(db, incident_id)
                if coordinator is None:
                    continue
                execution = await _latest_execution(db, incident_id)
                evidence = await _latest_evidence(db, incident_id)
                turn_count = await _agent_turn_count(db, incident_id)
                records.append(
                    build_openclaw_incumbent_record(
                        run_id=args.run_id,
                        incident_id=incident_id,
                        coordinator_output=coordinator.output_json,
                        execution_success=(
                            execution.success if execution is not None else None
                        ),
                        verification_result=(
                            evidence.verification_result if evidence is not None else None
                        ),
                        audit_trace_complete=turn_count >= 3,
                        latency_ms=float(coordinator.latency_ms or 0),
                        coordinator_degraded=bool(coordinator.degraded),
                    )
                )
    except Exception as exc:
        print(
            json.dumps(
                {
                    "error": "openclaw_incumbent_export_failed",
                    "detail": str(exc),
                    "output": args.output,
                    "run_id": args.run_id,
                },
                ensure_ascii=False,
                sort_keys=True,
            )
        )
        return 2

    output = Path(args.output)
    with output.open("w", encoding="utf-8") as handle:
        for record in records:
            handle.write(json.dumps(record.__dict__, ensure_ascii=False, sort_keys=True))
            handle.write("\n")

    print(
        json.dumps(
            {
                "output": str(output),
                "records": len(records),
                "run_id": args.run_id,
            },
            ensure_ascii=False,
            sort_keys=True,
        )
    )
    return 0


async def _incident_ids(db, *, cutoff, limit: int) -> list[str]:
    stmt = (
        select(AgentSession.incident_id)
        .where(
            and_(
                AgentSession.agent_role == "coordinator",
                AgentSession.created_at >= cutoff,
            )
        )
        .distinct()
        .order_by(AgentSession.incident_id.desc())
        .limit(limit)
    )
    result = await db.execute(stmt)
    return [str(row[0]) for row in result.all()]


async def _latest_coordinator(db, incident_id: str):
    stmt = (
        select(AgentSession)
        .where(
            and_(
                AgentSession.incident_id == incident_id,
                AgentSession.agent_role == "coordinator",
            )
        )
        .order_by(AgentSession.created_at.desc())
        .limit(1)
    )
    result = await db.execute(stmt)
    return result.scalar_one_or_none()


async def _latest_execution(db, incident_id: str):
    stmt = (
        select(AutoRepairExecution)
        .where(AutoRepairExecution.incident_id == incident_id)
        .order_by(AutoRepairExecution.created_at.desc())
        .limit(1)
    )
    result = await db.execute(stmt)
    return result.scalar_one_or_none()


async def _latest_evidence(db, incident_id: str):
    stmt = (
        select(IncidentEvidence)
        .where(IncidentEvidence.incident_id == incident_id)
        .order_by(IncidentEvidence.collected_at.desc())
        .limit(1)
    )
    result = await db.execute(stmt)
    return result.scalar_one_or_none()


async def _agent_turn_count(db, incident_id: str) -> int:
    stmt = select(func.count()).select_from(AgentSession).where(
        AgentSession.incident_id == incident_id
    )
    result = await db.execute(stmt)
    return int(result.scalar() or 0)


def main() -> int:
    return asyncio.run(main_async())


if __name__ == "__main__":
    raise SystemExit(main())
