"""Audit — security audit logging and evidence tracking.

Audit tracks security-relevant events across the system:
- user, agent, task, model, tool, action
- policy decision, approval, result, error
- resource usage, latency, network action
- memory write, security alert

All events are timestamped and immutable once recorded.
"""

from __future__ import annotations

import time
import uuid
from dataclasses import dataclass, field
from enum import Enum
from typing import Any


class AuditEventType(str, Enum):
    """Types of audit events."""

    USER_ACTION = "user_action"
    AGENT_STARTED = "agent_started"
    AGENT_FINISHED = "agent_finished"
    TASK_CREATED = "task_created"
    TASK_STARTED = "task_started"
    TASK_FINISHED = "task_finished"
    TOOL_CALLED = "tool_called"
    TOOL_RESULT = "tool_result"
    MODEL_DISCOVERED = "model_discovered"
    MODEL_VALIDATED = "model_validated"
    MODEL_FAILED = "model_failed"
    POLICY_DECISION = "policy_decision"
    APPROVAL_REQUIRED = "approval_required"
    APPROVAL_GRANTED = "approval_granted"
    APPROVAL_DENIED = "approval_denied"
    SECURITY_ALERT = "security_alert"
    RESOURCE_LIMIT = "resource_limit"
    MEMORY_UPDATED = "memory_updated"
    IDENTITY_CHECK = "identity_check"
    PERMISSION_CHECK = "permission_check"
    FIREWALL_CHECK = "firewall_check"
    DATA_ACCESS = "data_access"
    CONFIG_CHANGE = "config_change"
    ERROR = "error"


class AuditEventStatus(str, Enum):
    """Status of an audit event."""

    RECORDED = "recorded"
    CORRELATED = "correlated"
    ARCHIVED = "archived"


@dataclass
class AuditEvent:
    """A single audit event."""

    event_id: str
    event_type: AuditEventType
    timestamp: float
    actor: str = ""
    agent_id: str = ""
    task_id: str = ""
    model: str = ""
    tool: str = ""
    action: str = ""
    resource: str = ""
    policy_decision: str = ""
    approval_id: str = ""
    result: str = ""
    error: str = ""
    resource_usage: dict[str, Any] = field(default_factory=dict)
    latency_ms: float = 0.0
    network_action: str = ""
    memory_write: str = ""
    security_alert: str = ""
    metadata: dict[str, Any] = field(default_factory=dict)
    status: AuditEventStatus = AuditEventStatus.RECORDED


@dataclass
class AuditQuery:
    """Query parameters for filtering audit events."""

    event_type: AuditEventType | None = None
    actor: str | None = None
    agent_id: str | None = None
    task_id: str | None = None
    action: str | None = None
    resource: str | None = None
    since: float | None = None
    until: float | None = None
    limit: int = 100


class AuditLog:
    """Immutable audit log for security events.

    Events are appended-only and cannot be modified or deleted.
    This ensures audit integrity and prevents tampering.

    Usage:
        audit = AuditLog()
        audit.record(AuditEventType.SECURITY_ALERT, agent_id="agent-1",
                      security_alert="suspicious activity detected")
        events = audit.query(agent_id="agent-1")
    """

    def __init__(self) -> None:
        self._events: list[AuditEvent] = []

    def record(
        self,
        event_type: AuditEventType,
        actor: str = "",
        agent_id: str = "",
        task_id: str = "",
        model: str = "",
        tool: str = "",
        action: str = "",
        resource: str = "",
        policy_decision: str = "",
        approval_id: str = "",
        result: str = "",
        error: str = "",
        resource_usage: dict[str, Any] | None = None,
        latency_ms: float = 0.0,
        network_action: str = "",
        memory_write: str = "",
        security_alert: str = "",
        metadata: dict[str, Any] | None = None,
    ) -> AuditEvent:
        """Record a new audit event.

        Returns the recorded event with a unique ID and timestamp.
        """
        event = AuditEvent(
            event_id=f"audit_{uuid.uuid4().hex[:16]}",
            event_type=event_type,
            timestamp=time.time(),
            actor=actor,
            agent_id=agent_id,
            task_id=task_id,
            model=model,
            tool=tool,
            action=action,
            resource=resource,
            policy_decision=policy_decision,
            approval_id=approval_id,
            result=result,
            error=error,
            resource_usage=resource_usage or {},
            latency_ms=latency_ms,
            network_action=network_action,
            memory_write=memory_write,
            security_alert=security_alert,
            metadata=metadata or {},
        )
        self._events.append(event)
        return event

    def get(self, event_id: str) -> AuditEvent | None:
        """Retrieve an event by its ID."""
        for event in self._events:
            if event.event_id == event_id:
                return event
        return None

    def query(self, params: AuditQuery | None = None) -> list[AuditEvent]:
        """Query events with optional filters.

        Returns events matching all specified criteria,
        most recent first, limited by params.limit.
        """
        params = params or AuditQuery()
        results: list[AuditEvent] = []

        for event in self._events:
            if params.event_type is not None and event.event_type != params.event_type:
                continue
            if params.actor is not None and event.actor != params.actor:
                continue
            if params.agent_id is not None and event.agent_id != params.agent_id:
                continue
            if params.task_id is not None and event.task_id != params.task_id:
                continue
            if params.action is not None and event.action != params.action:
                continue
            if params.resource is not None and event.resource != params.resource:
                continue
            if params.since is not None and event.timestamp < params.since:
                continue
            if params.until is not None and event.timestamp > params.until:
                continue

            results.append(event)

        results.sort(key=lambda e: e.timestamp, reverse=True)
        return results[: params.limit]

    def count(self) -> int:
        """Total number of recorded events."""
        return len(self._events)

    def count_by_type(self, event_type: AuditEventType) -> int:
        """Count events of a specific type."""
        return sum(1 for e in self._events if e.event_type == event_type)

    def list_all(self, limit: int = 100) -> list[AuditEvent]:
        """List all events, most recent first."""
        events = sorted(self._events, key=lambda e: e.timestamp, reverse=True)
        return events[:limit]

    def clear(self) -> None:
        """Clear all events (for testing only)."""
        self._events.clear()


__all__ = [
    "AuditEvent",
    "AuditEventStatus",
    "AuditEventType",
    "AuditLog",
    "AuditQuery",
]
