from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime, timezone
import json
import os
import time
from typing import Any, Callable, Iterable


AuditSink = Callable[["AuditEvent"], None]


@dataclass(frozen=True)
class AuditEvent:
    event_type: str
    run_id: str
    tool_name: str | None
    agent_id: str | None
    tool_call_id: str | None = None
    context_id: str | None = None
    active_tags: list[str] = field(default_factory=list)
    active_tags_after: list[str] | None = None
    tool_kind: str | None = None
    mcp_server: str | None = None
    reason: str | None = None
    boundary: str | None = None
    policy_reason: str | None = None
    decision: str | None = None
    enforced: bool | None = None
    would_block: bool | None = None
    would_require_approval: bool | None = None
    payload: dict[str, Any] | None = None
    mode: str | None = None
    level: str | None = None

    def as_dict(self) -> dict[str, Any]:
        ts_ms = int(time.time() * 1000)
        ts = datetime.fromtimestamp(ts_ms / 1000, tz=timezone.utc).isoformat()
        mode = self.mode or _current_mode()
        level = self.level or _level_for_event(self.event_type)
        data: dict[str, Any] = {
            "ts": ts,
            "ts_ms": ts_ms,
            "schema_version": 1,
            "run_id": self.run_id,
            "mode": mode,
            "level": level,
            "event_type": self.event_type,
            "tool_kind": self.tool_kind,
            "tool_name": self.tool_name,
            "tool_call_id": self.tool_call_id,
            "context_id": self.context_id,
            "mcp_server": self.mcp_server,
            "agent_id": self.agent_id,
            "active_tags": self.active_tags,
            "active_tags_after": self.active_tags_after,
            "boundary": self.boundary,
            "reason": self.reason,
            "policy_reason": self.policy_reason,
            "decision": self.decision,
            "enforced": self.enforced,
            "would_block": self.would_block,
            "would_require_approval": self.would_require_approval,
            "payload": self.payload,
        }
        return {key: value for key, value in data.items() if value is not None}


def default_audit_path() -> str:
    return os.path.join(os.getcwd(), "rgltr-audit.jsonl")


class AuditLogger:
    def __init__(self, file: str | None = None) -> None:
        self._file = file or default_audit_path()

    def __call__(self, event: AuditEvent) -> None:
        line = json.dumps(event.as_dict(), sort_keys=False)
        with open(self._file, "a", encoding="utf-8") as handle:
            handle.write(line + "\n")


def emit_event(sink: AuditSink | None, event: AuditEvent) -> None:
    if sink is None:
        return
    sink(event)


def tags_to_strings(tags: Iterable[Any]) -> list[str]:
    return [getattr(tag, "value", str(tag)) for tag in tags]


def _current_mode() -> str:
    try:
        from .config import get_config
    except Exception:
        return "unknown"
    return get_config().mode


def _level_for_event(event_type: str) -> str:
    if event_type == "policy_decision":
        return "warn"
    return "info"
