"""SOX-compliant audit logger for the SDK.

Wraps ``databridge_core.audit.logger.AuditLogger`` with SDK-specific
context (workflow name, step name, result IDs) and adds governance
integration via ``src.governance.audit_trail``.
"""

from __future__ import annotations

import uuid
from dataclasses import dataclass, field
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Dict, List, Optional


@dataclass
class SDKAuditEntry:
    """A single SDK audit record.

    Extends the core ``AuditEntry`` with workflow context.
    """

    timestamp: str = field(
        default_factory=lambda: datetime.now(timezone.utc).isoformat()
    )
    action: str = ""
    workflow: str = ""
    step_name: str = ""
    entity_type: str = ""
    entity_id: Optional[str] = None
    user_id: Optional[str] = None
    result_id: Optional[str] = None
    trace_id: Optional[str] = None
    details: Optional[Dict[str, Any]] = None
    audit_id: str = field(default_factory=lambda: uuid.uuid4().hex[:12])

    def to_dict(self) -> Dict[str, Any]:
        return {
            "timestamp": self.timestamp,
            "action": self.action,
            "workflow": self.workflow,
            "step_name": self.step_name,
            "entity_type": self.entity_type,
            "entity_id": self.entity_id,
            "user_id": self.user_id,
            "result_id": self.result_id,
            "trace_id": self.trace_id,
            "details": self.details,
            "audit_id": self.audit_id,
        }


class AuditLogger:
    """SDK audit logger with SOX compliance.

    Reuses:
        - ``databridge_core.audit.logger.AuditLogger`` for CSV persistence
        - ``src.governance.audit_trail.query_audit_trail()`` for querying
        - ``src.graphrag.evidence.EvidenceTracker`` for evidence linkage

    Every SDK operation (workflow execution, compilation, agent design)
    produces an audit entry.  Entries are buffered and flushed periodically
    or on explicit ``flush()`` call.

    Usage::

        logger = AuditLogger(log_path=Path("data/sdk/audit.csv"))
        logger.log_workflow_start("reconciliation.hash_compare", params={...})
        logger.log_step("validate", status="success")
        logger.log_workflow_end("reconciliation.hash_compare", result_id="abc123")
        logger.flush()
    """

    def __init__(
        self,
        log_path: Optional[Path] = None,
        user_id: Optional[str] = None,
        buffer_size: int = 10,
    ):
        self._log_path = log_path or Path("data/sdk/audit.csv")
        self._user_id = user_id
        self._buffer_size = buffer_size
        self._buffer: List[SDKAuditEntry] = []
        self._core_logger = None

        self._log_path.parent.mkdir(parents=True, exist_ok=True)
        self._init_core_logger()

    def _init_core_logger(self) -> None:
        """Initialize the core AuditLogger if available."""
        try:
            from databridge_core.audit.logger import (
                AuditLogger as CoreAuditLogger,
            )

            self._core_logger = CoreAuditLogger(
                log_path=self._log_path,
                source="sdk",
                buffer_size=self._buffer_size,
            )
        except ImportError:
            self._core_logger = None

    def log(
        self,
        action: str,
        workflow: str = "",
        step_name: str = "",
        entity_type: str = "workflow",
        entity_id: Optional[str] = None,
        result_id: Optional[str] = None,
        details: Optional[Dict[str, Any]] = None,
    ) -> SDKAuditEntry:
        """Record an audit entry.

        Args:
            action: Action performed (e.g. ``workflow_start``, ``step_execute``).
            workflow: Dotted workflow name.
            step_name: Step within the workflow.
            entity_type: Type of entity acted upon.
            entity_id: ID of the entity.
            result_id: Associated Result.result_id.
            details: Extra details dict.

        Returns:
            The created audit entry.
        """
        trace_id = (details or {}).get("trace_id") if details else None
        entry = SDKAuditEntry(
            action=action,
            workflow=workflow,
            step_name=step_name,
            entity_type=entity_type,
            entity_id=entity_id,
            user_id=self._user_id,
            result_id=result_id,
            trace_id=trace_id,
            details=details,
        )
        self._buffer.append(entry)

        if self._core_logger:
            self._core_logger.log(
                action=action,
                entity_type=entity_type,
                entity_id=entity_id,
                user_id=self._user_id,
                details={
                    "workflow": workflow,
                    "step_name": step_name,
                    "result_id": result_id,
                    **(details or {}),
                },
                source="sdk",
            )

        if len(self._buffer) >= self._buffer_size:
            self.flush()

        return entry

    def log_workflow_start(
        self, workflow: str, params: Optional[Dict[str, Any]] = None
    ) -> SDKAuditEntry:
        return self.log(
            action="workflow_start",
            workflow=workflow,
            details={"parameters": params},
        )

    def log_step(
        self,
        step_name: str,
        workflow: str = "",
        status: str = "success",
        data: Optional[Dict[str, Any]] = None,
    ) -> SDKAuditEntry:
        return self.log(
            action="step_execute",
            workflow=workflow,
            step_name=step_name,
            details={"status": status, "data_summary": _summarize(data)},
        )

    def log_workflow_end(
        self,
        workflow: str,
        result_id: str = "",
        status: str = "success",
    ) -> SDKAuditEntry:
        return self.log(
            action="workflow_end",
            workflow=workflow,
            result_id=result_id,
            details={"status": status},
        )

    def flush(self) -> None:
        """Flush buffered entries to disk."""
        if self._core_logger:
            self._core_logger.flush()
        self._buffer.clear()

    def get_recent(self, limit: int = 50) -> List[Dict[str, Any]]:
        """Return recent audit entries.

        Reuse: ``databridge_core.audit.logger.AuditLogger.get_recent_entries()``
        """
        if self._core_logger:
            return [e.to_dict() for e in self._core_logger.get_recent_entries(limit)]
        return [e.to_dict() for e in self._buffer[-limit:]]


def _summarize(data: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
    """Create a safe summary of step data (no raw rows)."""
    if not data:
        return None
    summary = {}
    for k, v in data.items():
        if isinstance(v, list):
            summary[k] = f"[{len(v)} items]"
        elif isinstance(v, dict):
            summary[k] = f"{{{len(v)} keys}}"
        else:
            summary[k] = v
    return summary
