"""Tamper-evident audit trail with SHA-256 hash chain."""

from __future__ import annotations

import csv
import hashlib
import json
import logging
import threading
import time
import uuid
from typing import Any

from horizon.compliance._store import ComplianceStore
from horizon.compliance._types import AuditEvent, AuditEventType

logger = logging.getLogger("horizon.compliance.audit")


class AuditTrail:
    """Append-only audit trail with hash-chain integrity.

    Every event is linked to its predecessor via SHA-256, forming a chain
    that an auditor can verify end-to-end. Any insertion, deletion, or
    modification of a past event breaks the chain at that point.
    """

    def __init__(self, store: ComplianceStore) -> None:
        self._store = store
        self._lock = threading.Lock()
        # Resume chain from last persisted event
        self._prev_hash = store.last_event_hash() or "genesis"

    def record(
        self,
        event_type: AuditEventType,
        actor: str,
        details: dict[str, Any],
        market_id: str | None = None,
        order_id: str | None = None,
        exchange: str | None = None,
    ) -> AuditEvent:
        """Record an audit event and append it to the hash chain."""
        event_id = uuid.uuid4().hex
        ts = time.time()

        with self._lock:
            # Build canonical form for hashing
            canonical = json.dumps(
                {
                    "event_id": event_id,
                    "event_type": event_type.value,
                    "timestamp": ts,
                    "actor": actor,
                    "details": details,
                    "market_id": market_id,
                    "order_id": order_id,
                    "exchange": exchange,
                    "prev_hash": self._prev_hash,
                },
                sort_keys=True,
                separators=(",", ":"),
            )
            event_hash = hashlib.sha256(canonical.encode()).hexdigest()

            event = AuditEvent(
                event_id=event_id,
                event_type=event_type,
                timestamp=ts,
                actor=actor,
                details=details,
                market_id=market_id,
                order_id=order_id,
                exchange=exchange,
                prev_hash=self._prev_hash,
                event_hash=event_hash,
            )

            self._store.insert_audit_event(event)
            self._prev_hash = event_hash

        logger.debug("Audit: %s by %s [%s]", event_type.value, actor, event_id[:8])
        return event

    def query(
        self,
        start: float | None = None,
        end: float | None = None,
        event_type: str | None = None,
        market_id: str | None = None,
        limit: int = 1000,
    ) -> list[AuditEvent]:
        """Query audit events with optional filters."""
        return self._store.query_audit_events(start, end, event_type, market_id, limit)

    def verify_integrity(
        self,
        start: float | None = None,
        end: float | None = None,
    ) -> tuple[bool, int]:
        """Verify the hash chain is intact.

        Returns (is_valid, events_checked). If is_valid is False, the chain
        has been tampered with at some point in the queried range.
        """
        events = self._store.query_audit_events(start, end, limit=1_000_000)
        if not events:
            return True, 0

        checked = 0
        for event in events:
            canonical = json.dumps(
                {
                    "event_id": event.event_id,
                    "event_type": event.event_type.value,
                    "timestamp": event.timestamp,
                    "actor": event.actor,
                    "details": event.details,
                    "market_id": event.market_id,
                    "order_id": event.order_id,
                    "exchange": event.exchange,
                    "prev_hash": event.prev_hash,
                },
                sort_keys=True,
                separators=(",", ":"),
            )
            expected_hash = hashlib.sha256(canonical.encode()).hexdigest()
            if expected_hash != event.event_hash:
                logger.error(
                    "Audit chain broken at event %s (expected %s, got %s)",
                    event.event_id, expected_hash, event.event_hash,
                )
                return False, checked
            checked += 1

        return True, checked

    def export_csv(self, path: str, start: float | None = None, end: float | None = None) -> int:
        """Export audit trail to CSV for regulatory submission."""
        events = self._store.query_audit_events(start, end, limit=1_000_000)
        with open(path, "w", newline="", encoding="utf-8") as f:
            writer = csv.writer(f)
            writer.writerow([
                "event_id", "event_type", "timestamp", "actor",
                "market_id", "order_id", "exchange", "details", "event_hash",
            ])
            for e in events:
                writer.writerow([
                    e.event_id, e.event_type.value, e.timestamp, e.actor,
                    e.market_id or "", e.order_id or "", e.exchange or "",
                    json.dumps(e.details), e.event_hash,
                ])
        return len(events)

    @property
    def count(self) -> int:
        return self._store.event_count()
