"""Hash-chained audit log for tamper-proof action recording."""

from __future__ import annotations

import hashlib
import json
from dataclasses import asdict, dataclass, field
from datetime import datetime, timezone
from typing import Any


@dataclass
class AuditEntry:
    """A single entry in the audit trail."""

    timestamp: str
    action: str
    params: dict[str, Any]
    allowed: bool
    matching_rule: str
    prev_hash: str
    hash: str


def _compute_hash(
    prev_hash: str,
    timestamp: str,
    action: str,
    params: dict[str, Any],
    allowed: bool,
    matching_rule: str,
) -> str:
    """Compute SHA-256 hash for an audit entry."""
    payload = (
        prev_hash
        + timestamp
        + action
        + json.dumps(params, sort_keys=True, default=str)
        + str(allowed)
        + matching_rule
    )
    return hashlib.sha256(payload.encode("utf-8")).hexdigest()


GENESIS_HASH = hashlib.sha256(b"").hexdigest()


class AuditLog:
    """Hash-chained audit log providing tamper-proof action recording."""

    def __init__(self) -> None:
        self._entries: list[AuditEntry] = []

    def add_entry(
        self,
        action: str,
        params: dict[str, Any],
        allowed: bool,
        matching_rule: str,
        timestamp: str | None = None,
    ) -> AuditEntry:
        """Record an action in the audit trail."""
        if timestamp is None:
            timestamp = datetime.now(timezone.utc).isoformat()

        prev_hash = self._entries[-1].hash if self._entries else GENESIS_HASH

        entry_hash = _compute_hash(
            prev_hash, timestamp, action, params, allowed, matching_rule
        )

        entry = AuditEntry(
            timestamp=timestamp,
            action=action,
            params=params,
            allowed=allowed,
            matching_rule=matching_rule,
            prev_hash=prev_hash,
            hash=entry_hash,
        )
        self._entries.append(entry)
        return entry

    def get_log(self) -> list[AuditEntry]:
        """Return all audit entries."""
        return list(self._entries)

    def export_json(self) -> str:
        """Export the full audit log as JSON."""
        return json.dumps(
            [asdict(e) for e in self._entries],
            indent=2,
            default=str,
        )

    def export_dicts(self) -> list[dict[str, Any]]:
        """Export the full audit log as a list of dicts."""
        return [asdict(e) for e in self._entries]

    def __len__(self) -> int:
        return len(self._entries)
