"""Horizon Compliance Module - regulatory compliance for prediction market trading.

Provides:
- Tamper-evident audit trail (SHA-256 hash chain)
- Trade surveillance (wash trading, spoofing, layering, rapid-fire, concentration)
- Human-in-the-loop pre-trade approval workflow
- Role-based access control (5 roles, hierarchical permissions)
- Regulatory position and exposure limits
- Compliance kill switch with RBAC
- Daily trade and position reports
- Data retention management (SEC Rule 17a-4)
- Pipeline integration via ``compliance_gate``
"""

from __future__ import annotations

import logging
from typing import Any

from horizon.compliance._types import (
    AuditEvent,
    AuditEventType,
    ApprovalRequest,
    ApprovalStatus,
    ComplianceAction,
    ComplianceConfig,
    ComplianceReport,
    DailyTradeReport,
    PositionReport,
    RegulatoryLimitConfig,
    Role,
    SurveillanceAlert,
    SurveillanceAlertType,
)
from horizon.compliance._store import ComplianceStore
from horizon.compliance._audit import AuditTrail
from horizon.compliance._surveillance import TradeSurveillance
from horizon.compliance._approval import ApprovalGateway
from horizon.compliance._access import AccessControl, PERMISSIONS
from horizon.compliance._limits import RegulatoryLimits
from horizon.compliance._reporting import ReportGenerator
from horizon.compliance._kill_switch import ComplianceKillSwitch
from horizon.compliance._retention import RetentionManager
from horizon.compliance._pipeline import compliance_gate

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

__all__ = [
    # Orchestrator
    "ComplianceManager",
    # Pipeline function
    "compliance_gate",
    # Config
    "ComplianceConfig",
    "RegulatoryLimitConfig",
    # Types / Enums
    "ComplianceAction",
    "AuditEventType",
    "SurveillanceAlertType",
    "Role",
    "ApprovalStatus",
    # Data classes
    "AuditEvent",
    "SurveillanceAlert",
    "ApprovalRequest",
    # Reports
    "ComplianceReport",
    "DailyTradeReport",
    "PositionReport",
    # Sub-components (for advanced usage)
    "ComplianceStore",
    "AuditTrail",
    "TradeSurveillance",
    "ApprovalGateway",
    "AccessControl",
    "RegulatoryLimits",
    "ReportGenerator",
    "ComplianceKillSwitch",
    "RetentionManager",
    "PERMISSIONS",
]


class ComplianceManager:
    """Central orchestrator for the compliance module.

    Owns all sub-components and provides a unified interface for the
    strategy runner and external tools (MCP, CLI, dashboard).

    Usage::

        from horizon.compliance import ComplianceManager, ComplianceConfig, Role

        config = ComplianceConfig(
            enabled=True,
            roles={"alice": Role.TRADER, "bob": Role.COMPLIANCE_OFFICER},
            approval_enabled=True,
            approval_threshold_notional=10_000,
        )
        compliance = ComplianceManager(config)
        compliance.bind_engine(engine)

        # In pipeline:
        hz.run(
            ...,
            pipeline=[compliance_gate, my_signal, my_sizer],
            params={"compliance": compliance},
        )

    Args:
        config: Compliance configuration.
        db_path: Override database path (default: from config or ./compliance.db).
    """

    def __init__(
        self,
        config: ComplianceConfig | None = None,
        db_path: str | None = None,
    ) -> None:
        if config is None:
            config = ComplianceConfig()
        self._config = config

        # Resolve DB path
        effective_db = db_path or config.db_path or "./compliance.db"

        # Initialize store (SQLite persistence)
        self._store = ComplianceStore(effective_db)

        # Initialize sub-components in dependency order
        self._audit = AuditTrail(self._store)
        self._access = AccessControl(config, self._store, self._audit)
        self._surveillance = TradeSurveillance(config, self._store, self._audit)
        self._approval = ApprovalGateway(config, self._store, self._audit)
        self._limits = RegulatoryLimits(config.regulatory_limits, self._store, self._audit)
        self._reporting = ReportGenerator(self._store, self._audit)
        self._kill_switch = ComplianceKillSwitch(self._audit, self._access)
        self._retention = RetentionManager(config, self._store, self._audit)
        self._engine: Any = None

        logger.info(
            "Compliance module initialized (audit=%s, surveillance=%s, approval=%s)",
            config.audit_enabled, config.surveillance_enabled, config.approval_enabled,
        )

    # --- Properties for sub-component access ---

    @property
    def config(self) -> ComplianceConfig:
        return self._config

    @property
    def store(self) -> ComplianceStore:
        return self._store

    @property
    def audit(self) -> AuditTrail:
        return self._audit

    @property
    def access(self) -> AccessControl:
        return self._access

    @property
    def surveillance(self) -> TradeSurveillance:
        return self._surveillance

    @property
    def approval(self) -> ApprovalGateway:
        return self._approval

    @property
    def limits(self) -> RegulatoryLimits:
        return self._limits

    @property
    def reporting(self) -> ReportGenerator:
        return self._reporting

    @property
    def kill_switch(self) -> ComplianceKillSwitch:
        return self._kill_switch

    @property
    def retention(self) -> RetentionManager:
        return self._retention

    # --- Engine binding ---

    def bind_engine(self, engine: Any) -> None:
        """Bind to the trading engine for position queries and kill switch."""
        self._engine = engine
        self._kill_switch.bind_engine(engine)

    # --- Convenience methods ---

    def check_order(
        self,
        market_id: str,
        side: str,
        price: float,
        size: float,
        actor: str = "system",
    ) -> ComplianceAction:
        """Run all pre-trade compliance checks on an order.

        Checks in order:
        1. Kill switch active → KILL_SWITCH
        2. Regulatory limits → REJECTED if breached
        3. Approval threshold → PENDING_APPROVAL if above threshold

        Returns ComplianceAction indicating the result.
        """
        if not self._config.enabled:
            return ComplianceAction.APPROVED

        # Kill switch check
        if self._kill_switch.is_active:
            return ComplianceAction.KILL_SWITCH

        # Regulatory limits
        if self._engine is not None:
            limit_result = self._limits.check_order(
                market_id, side, price, size, self._engine,
            )
            if limit_result == ComplianceAction.REJECTED:
                return ComplianceAction.REJECTED

        # Approval workflow
        if self._config.approval_enabled:
            order_data = {
                "market_id": market_id,
                "side": side,
                "price": price,
                "size": size,
            }
            approval_result = self._approval.check_order(order_data, actor, market_id)
            if approval_result != ComplianceAction.APPROVED:
                return approval_result

        # Record order for surveillance
        if self._config.surveillance_enabled:
            import time
            self._surveillance.record_order(time.time(), market_id, side, size, "")

        return ComplianceAction.APPROVED

    def record_fill(self, market_id: str, side: str, size: float, price: float) -> None:
        """Record a fill for surveillance and audit."""
        import time
        ts = time.time()
        if self._config.surveillance_enabled:
            self._surveillance.record_fill(ts, market_id, side, size)
        if self._config.audit_enabled:
            self._audit.record(
                AuditEventType.ORDER_FILLED, "system",
                {"market_id": market_id, "side": side, "size": size, "price": price,
                 "notional": price * size},
                market_id=market_id,
            )

    def record_cancel(self, order_id: str, market_id: str = "") -> None:
        """Record an order cancellation for surveillance."""
        import time
        if self._config.surveillance_enabled:
            self._surveillance.record_cancel(time.time(), order_id, market_id)

    def on_cycle(self, engine: Any = None) -> list[SurveillanceAlert]:
        """Run per-cycle compliance tasks. Call from the strategy loop.

        Returns any new surveillance alerts generated this cycle.
        """
        if not self._config.enabled:
            return []

        eng = engine or self._engine
        alerts: list[SurveillanceAlert] = []

        # Surveillance analysis
        if self._config.surveillance_enabled:
            try:
                alerts = self._surveillance.analyze_cycle(eng)
            except Exception as e:
                logger.debug("Surveillance cycle error: %s", e)

        # Expire stale approvals
        try:
            self._approval.expire_stale()
        except Exception:
            pass

        return alerts

    def daily_report(self, date: str | None = None) -> DailyTradeReport:
        """Generate daily trade report."""
        return self._reporting.daily_trade_report(date)

    def position_report(self) -> PositionReport:
        """Generate current position report."""
        if self._engine is None:
            raise RuntimeError("No engine bound")
        return self._reporting.position_report(self._engine)

    def compliance_report(self, period_start: float, period_end: float) -> ComplianceReport:
        """Generate full compliance report for a time period."""
        if self._engine is None:
            raise RuntimeError("No engine bound")
        return self._reporting.compliance_report(period_start, period_end, self._engine)

    def verify_audit_integrity(
        self, start: float | None = None, end: float | None = None,
    ) -> tuple[bool, int]:
        """Verify the audit trail hash chain integrity."""
        return self._audit.verify_integrity(start, end)

    def export_audit(
        self, path: str, start: float | None = None, end: float | None = None,
    ) -> int:
        """Export audit trail to CSV."""
        return self._audit.export_csv(path, start, end)

    def close(self) -> None:
        """Close the compliance store connection."""
        self._store.close()

    def status(self) -> dict[str, Any]:
        """Return full compliance status."""
        return {
            "enabled": self._config.enabled,
            "audit_events": self._audit.count,
            "kill_switch": self._kill_switch.status(),
            "pending_approvals": len(self._approval.pending()),
            "recent_alerts": [a.to_dict() for a in self._surveillance.recent_alerts],
            "roles": self._access.list_roles(),
            "limit_utilization": (
                self._limits.current_utilization(self._engine)
                if self._engine else {}
            ),
        }
