"""
eaigins_sdk.policy
──────────────────
Stage 3: Policy Enforcement Gateway

Define governance rules as ``Policy`` objects and register them
on a ``PolicyGateway``.  The SDK ships with built-in policy sets
for common domains; you can extend or replace them.

Built-in policy sets (importable from eaigins_sdk.policies.*):
    - eaigins_sdk.policies.financial  — BSA / FATF / AML
    - eaigins_sdk.policies.healthcare — HIPAA / FDA 21 CFR
    - eaigins_sdk.policies.customercare — GDPR / CCPA / PCI-DSS

Example — custom policy::

    from eaigins_sdk.policy import Policy, PolicyGateway

    my_policy = Policy(
        policy_id="MY-001",
        name="No weekend deployments",
        description="AI agents may not trigger deployments on weekends.",
        category="OPERATIONAL",
        requires_human_approval=False,
        blocks_action=True,
        evaluate=lambda a: (
            a.tool_name != "deploy_to_production" or
            __import__("datetime").datetime.now().weekday() < 5,
            "Deployments on weekends are blocked."
        )
    )

    gw = PolicyGateway(policies=[my_policy])
    result = gw.evaluate(action)
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Callable, Optional

from .models import AgentAction, PolicyResult


# ── Policy dataclass ──────────────────────────────────────────────────────────

@dataclass
class Policy:
    """
    A single declarative governance rule.

    The ``evaluate`` callable receives an ``AgentAction`` and returns
    ``(passed: bool, message: str)``.

    Args:
        policy_id:              Unique identifier, e.g. ``"POL-001"``.
        name:                   Human-readable rule name.
        description:            What this rule protects against.
        category:               ``"DATA_GOVERNANCE" | "OPERATIONAL" | "REGULATORY"``.
        evaluate:               ``(AgentAction) -> (bool, str)`` — True = policy passed.
        requires_human_approval: If violated, queue for human review (ESCALATE).
        blocks_action:          If violated, hard-block immediately (BLOCK).
    """
    policy_id:              str
    name:                   str
    description:            str
    category:               str
    evaluate:               Callable[[AgentAction], tuple[bool, str]]
    requires_human_approval: bool = False
    blocks_action:          bool = False


# ── Gateway ───────────────────────────────────────────────────────────────────

class PolicyGateway:
    """
    Evaluates an ``AgentAction`` against a registered list of policies.

    Usage::

        from eaigins_sdk.policy import PolicyGateway
        from eaigins_sdk.policies.financial import AML_POLICIES

        gw = PolicyGateway(policies=AML_POLICIES)
        result = gw.evaluate(action)

    Add policies at runtime::

        gw.add(my_custom_policy)
        gw.add_many([pol1, pol2])
    """

    def __init__(self, policies: Optional[list[Policy]] = None):
        self.policies: list[Policy] = list(policies or [])

    def add(self, policy: Policy) -> "PolicyGateway":
        """Add a single policy and return self for chaining."""
        self.policies.append(policy)
        return self

    def add_many(self, policies: list[Policy]) -> "PolicyGateway":
        """Add multiple policies and return self for chaining."""
        self.policies.extend(policies)
        return self

    def evaluate(self, action: AgentAction) -> PolicyResult:
        """Evaluate ``action`` against all registered policies."""
        violated:  list[str] = []
        approvals: list[str] = []
        details:   list[str] = []
        hard_block = False

        for policy in self.policies:
            try:
                passed, message = policy.evaluate(action)
            except Exception as exc:
                passed, message = True, f"Policy eval error (skipped): {exc}"

            if not passed:
                violated.append(f"[{policy.policy_id}] {policy.name}")
                details.append(f"  ↳ {message}")
                if policy.requires_human_approval:
                    approvals.append(f"{policy.policy_id}: {policy.name}")
                if policy.blocks_action:
                    hard_block = True

        if violated:
            summary = (
                f"{'BLOCKED' if hard_block else 'FLAGGED'}: "
                f"{len(violated)} violation(s).\n" + "\n".join(details)
            )
        else:
            summary = f"All {len(self.policies)} policies passed."

        return PolicyResult(
            passed=not hard_block and not violated,
            violated_policies=violated,
            required_approvals=approvals,
            details=summary,
        )

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

    def __repr__(self) -> str:
        return f"PolicyGateway({len(self.policies)} policies)"
