from __future__ import annotations

import json
from pathlib import Path
from typing import TYPE_CHECKING, Any

from niannian.external_data.schema import utc_now_iso

if TYPE_CHECKING:
    from niannian.external_data.schema import ExternalDataRequest, ExternalDataResult


def audit_path(home: Path, project: str) -> Path:
    return home / "external" / project / "_audit.jsonl"


def append_tool_audit(home: Path, project: str, row: dict[str, Any]) -> None:
    path = audit_path(home, project)
    path.parent.mkdir(parents=True, exist_ok=True)
    with path.open("a", encoding="utf-8") as f:
        f.write(json.dumps(row, ensure_ascii=False) + "\n")


def build_audit_row(
    req: ExternalDataRequest,
    result: ExternalDataResult,
    *,
    learn_applied: bool = False,
) -> dict[str, Any]:
    row: dict[str, Any] = {
        "received_at": utc_now_iso(),
        "occurred_at": req.occurred_at,
        "trace_id": "",
        "actor": {"user_id": "unknown"},
        "learn_applied": learn_applied,
        "ok": result.ok,
        "operation": result.operation,
        "record_id": result.record_id,
        "function": result.function,
    }
    if req.provenance is not None:
        row["trace_id"] = req.provenance.trace_id
        actor: dict[str, str] = {"user_id": req.provenance.actor.user_id}
        if req.provenance.actor.display_name:
            actor["display_name"] = req.provenance.actor.display_name
        row["actor"] = actor
    if req.capability_id:
        row["capability_id"] = req.capability_id
    return row


def read_tool_audit(
    home: Path,
    project: str,
    *,
    since: str = "",
    until: str = "",
    actor: str = "",
    trace_id: str = "",
) -> list[dict[str, Any]]:
    path = audit_path(home, project)
    since_val = str(since or "").strip()
    until_val = str(until or "").strip()
    actor_val = str(actor or "").strip()
    trace_val = str(trace_id or "").strip()
    entries: list[dict[str, Any]] = []
    if not path.is_file():
        return entries
    for line in path.read_text(encoding="utf-8").strip().split("\n"):
        if not line:
            continue
        try:
            row = json.loads(line)
        except json.JSONDecodeError:
            continue
        ts = str(row.get("received_at") or row.get("occurred_at") or "")
        if since_val and ts and ts < since_val:
            continue
        if until_val and ts and ts > until_val:
            continue
        if actor_val:
            user_id = str((row.get("actor") or {}).get("user_id") or "")
            if user_id != actor_val:
                continue
        if trace_val and str(row.get("trace_id") or "") != trace_val:
            continue
        entries.append(row)
    return entries
