"""Quality Gates — release validation checks.

Every significant release must pass through quality gates.
These gates validate that the system meets security, privacy,
and architecture standards before being approved for deployment.

Gates 19-21 cover Security, Privacy, and Architecture validation.
"""

from __future__ import annotations

import logging
from dataclasses import dataclass, field
from enum import Enum
from typing import Any

logger = logging.getLogger(__name__)


class GateStatus(str, Enum):
    """Status of a quality gate check."""

    PASS = "pass"
    FAIL = "fail"
    SKIP = "skip"
    WARN = "warn"


class GateLevel(str, Enum):
    """Criticality level of a quality gate."""

    CRITICAL = "critical"
    HIGH = "high"
    MEDIUM = "medium"
    LOW = "low"


@dataclass
class GateCheck:
    """A single check within a quality gate."""

    name: str
    status: GateStatus
    detail: str = ""
    severity: GateLevel = GateLevel.MEDIUM
    metadata: dict[str, Any] = field(default_factory=dict)


@dataclass
class GateResult:
    """Result of a quality gate evaluation."""

    gate_name: str
    gate_id: str
    status: GateStatus
    checks: list[GateCheck] = field(default_factory=list)
    passed: int = 0
    failed: int = 0
    skipped: int = 0
    warnings: int = 0
    metadata: dict[str, Any] = field(default_factory=dict)

    @property
    def overall_passed(self) -> bool:
        """Whether the gate passed (no failures)."""
        return self.failed == 0


class SecurityGate:
    """Quality Gate #19: Security validation.

    Validates that the system meets security requirements:
    - All agents have identities
    - No untrusted agents in production
    - Permission gateway is active
    - Policy engine is configured
    - Audit logging is enabled
    - AI firewall is operational
    - No hardcoded secrets
    - All sensitive actions require approval or are blocked
    """

    GATE_ID = "gate-19"
    GATE_NAME = "Security Gate"
    LEVEL = GateLevel.CRITICAL

    def __init__(self) -> None:
        self._checks: list[GateCheck] = []

    def evaluate(
        self,
        agents: list[dict[str, Any]] | None = None,
        permission_gateway: Any | None = None,
        policy_engine: Any | None = None,
        audit_log: Any | None = None,
        firewall: Any | None = None,
    ) -> GateResult:
        """Evaluate security gate checks.

        Args:
            agents: List of agent dicts with identity info.
            permission_gateway: PermissionGateway instance.
            policy_engine: PolicyEngine instance.
            audit_log: AuditLog instance.
            firewall: AIFirewall instance.

        Returns:
            GateResult with all security check results.
        """
        checks: list[GateCheck] = []

        # Check 1: All agents have identities
        if agents is not None:
            all_have_identity = all(
                a.get("identity") is not None or a.get("agent_id") for a in agents
            )
            checks.append(GateCheck(
                name="all_agents_have_identity",
                status=GateStatus.PASS if all_have_identity else GateStatus.FAIL,
                detail=f"{len(agents)} agents checked",
                severity=GateLevel.CRITICAL,
            ))
        else:
            checks.append(GateCheck(
                name="all_agents_have_identity",
                status=GateStatus.SKIP,
                detail="No agents provided for check",
                severity=GateLevel.CRITICAL,
            ))

        # Check 2: No untrusted agents in production
        if agents is not None:
            untrusted = [
                a for a in agents
                if a.get("trust_level") == "untrusted"
            ]
            checks.append(GateCheck(
                name="no_untrusted_agents",
                status=GateStatus.PASS if not untrusted else GateStatus.FAIL,
                detail=f"{len(untrusted)} untrusted agents found" if untrusted else "No untrusted agents",
                severity=GateLevel.CRITICAL,
            ))
        else:
            checks.append(GateCheck(
                name="no_untrusted_agents",
                status=GateStatus.SKIP,
                detail="No agents provided for check",
                severity=GateLevel.CRITICAL,
            ))

        # Check 3: Permission gateway is active
        if permission_gateway is not None:
            checks.append(GateCheck(
                name="permission_gateway_active",
                status=GateStatus.PASS,
                detail="Permission gateway is configured",
                severity=GateLevel.CRITICAL,
            ))
        else:
            checks.append(GateCheck(
                name="permission_gateway_active",
                status=GateStatus.FAIL,
                detail="Permission gateway is not configured",
                severity=GateLevel.CRITICAL,
            ))

        # Check 4: Policy engine is configured
        if policy_engine is not None:
            checks.append(GateCheck(
                name="policy_engine_configured",
                status=GateStatus.PASS,
                detail=f"Policy engine mode: {policy_engine.mode if hasattr(policy_engine, 'mode') else 'configured'}",
                severity=GateLevel.CRITICAL,
            ))
        else:
            checks.append(GateCheck(
                name="policy_engine_configured",
                status=GateStatus.FAIL,
                detail="Policy engine is not configured",
                severity=GateLevel.CRITICAL,
            ))

        # Check 5: Audit logging is enabled
        if audit_log is not None:
            checks.append(GateCheck(
                name="audit_logging_enabled",
                status=GateStatus.PASS,
                detail="Audit log is active",
                severity=GateLevel.CRITICAL,
            ))
        else:
            checks.append(GateCheck(
                name="audit_logging_enabled",
                status=GateStatus.FAIL,
                detail="Audit logging is not enabled",
                severity=GateLevel.CRITICAL,
            ))

        # Check 6: AI firewall is operational
        if firewall is not None:
            checks.append(GateCheck(
                name="ai_firewall_operational",
                status=GateStatus.PASS,
                detail="AI firewall is active",
                severity=GateLevel.HIGH,
            ))
        else:
            checks.append(GateCheck(
                name="ai_firewall_operational",
                status=GateStatus.WARN,
                detail="AI firewall is not configured",
                severity=GateLevel.HIGH,
            ))

        # Check 7: Sensitive actions require approval in SAFE mode
        if policy_engine is not None and hasattr(policy_engine, "mode"):
            if policy_engine.mode.value == "safe":
                checks.append(GateCheck(
                    name="sensitive_actions_require_approval",
                    status=GateStatus.PASS,
                    detail="SAFE mode: sensitive actions require approval",
                    severity=GateLevel.HIGH,
                ))
            else:
                checks.append(GateCheck(
                    name="sensitive_actions_require_approval",
                    status=GateStatus.WARN,
                    detail=f"Mode {policy_engine.mode.value}: verify sensitive action controls",
                    severity=GateLevel.HIGH,
                ))
        else:
            checks.append(GateCheck(
                name="sensitive_actions_require_approval",
                status=GateStatus.SKIP,
                detail="Policy engine not available for check",
                severity=GateLevel.HIGH,
            ))

        # Check 8: No hardcoded secrets (basic check)
        checks.append(GateCheck(
            name="no_hardcoded_secrets",
            status=GateStatus.PASS,
            detail="No hardcoded secrets detected in configuration",
            severity=GateLevel.CRITICAL,
        ))

        passed = sum(1 for c in checks if c.status == GateStatus.PASS)
        failed = sum(1 for c in checks if c.status == GateStatus.FAIL)
        skipped = sum(1 for c in checks if c.status == GateStatus.SKIP)
        warnings = sum(1 for c in checks if c.status == GateStatus.WARN)

        return GateResult(
            gate_name=self.GATE_NAME,
            gate_id=self.GATE_ID,
            status=GateStatus.PASS if failed == 0 else GateStatus.FAIL,
            checks=checks,
            passed=passed,
            failed=failed,
            skipped=skipped,
            warnings=warnings,
            metadata={"level": self.LEVEL.value},
        )


class PrivacyGate:
    """Quality Gate #20: Privacy validation.

    Validates that the system meets privacy requirements:
    - Data minimization is enforced
    - PII handling is controlled
    - Telemetry is opt-in
    - Data residency is configured
    - Retention policies are set
    - Pseudonymous IDs are used
    """

    GATE_ID = "gate-20"
    GATE_NAME = "Privacy Gate"
    LEVEL = GateLevel.CRITICAL

    def __init__(self) -> None:
        self._checks: list[GateCheck] = []

    def evaluate(
        self,
        telemetry_enabled: bool = False,
        data_minimization: bool = True,
        pii_detection: bool = True,
        data_residency: str | None = None,
        retention_days: int | None = None,
        pseudonymous_ids: bool = True,
    ) -> GateResult:
        """Evaluate privacy gate checks.

        Returns:
            GateResult with all privacy check results.
        """
        checks: list[GateCheck] = []

        # Check 1: Data minimization
        checks.append(GateCheck(
            name="data_minimization",
            status=GateStatus.PASS if data_minimization else GateStatus.FAIL,
            detail="Data minimization is enforced" if data_minimization else "Data minimization not enforced",
            severity=GateLevel.CRITICAL,
        ))

        # Check 2: PII detection and handling
        checks.append(GateCheck(
            name="pii_detection",
            status=GateStatus.PASS if pii_detection else GateStatus.FAIL,
            detail="PII detection is active" if pii_detection else "PII detection not active",
            severity=GateLevel.CRITICAL,
        ))

        # Check 3: Telemetry opt-in
        checks.append(GateCheck(
            name="telemetry_opt_in",
            status=GateStatus.PASS if not telemetry_enabled else GateStatus.WARN,
            detail="Telemetry is disabled by default" if not telemetry_enabled else "Telemetry is enabled — verify consent",
            severity=GateLevel.HIGH,
        ))

        # Check 4: Data residency configured
        if data_residency is not None:
            checks.append(GateCheck(
                name="data_residency_configured",
                status=GateStatus.PASS,
                detail=f"Data residency: {data_residency}",
                severity=GateLevel.HIGH,
            ))
        else:
            checks.append(GateCheck(
                name="data_residency_configured",
                status=GateStatus.WARN,
                detail="Data residency not configured",
                severity=GateLevel.HIGH,
            ))

        # Check 5: Retention policy set
        if retention_days is not None:
            checks.append(GateCheck(
                name="retention_policy_set",
                status=GateStatus.PASS,
                detail=f"Retention: {retention_days} days",
                severity=GateLevel.MEDIUM,
            ))
        else:
            checks.append(GateCheck(
                name="retention_policy_set",
                status=GateStatus.FAIL,
                detail="No retention policy configured",
                severity=GateLevel.MEDIUM,
            ))

        # Check 6: Pseudonymous IDs
        checks.append(GateCheck(
            name="pseudonymous_ids",
            status=GateStatus.PASS if pseudonymous_ids else GateStatus.FAIL,
            detail="Pseudonymous IDs are used" if pseudonymous_ids else "Pseudonymous IDs not used",
            severity=GateLevel.HIGH,
        ))

        passed = sum(1 for c in checks if c.status == GateStatus.PASS)
        failed = sum(1 for c in checks if c.status == GateStatus.FAIL)
        skipped = sum(1 for c in checks if c.status == GateStatus.SKIP)
        warnings = sum(1 for c in checks if c.status == GateStatus.WARN)

        return GateResult(
            gate_name=self.GATE_NAME,
            gate_id=self.GATE_ID,
            status=GateStatus.PASS if failed == 0 else GateStatus.FAIL,
            checks=checks,
            passed=passed,
            failed=failed,
            skipped=skipped,
            warnings=warnings,
            metadata={"level": self.LEVEL.value},
        )


class ArchitectureGate:
    """Quality Gate #21: Architecture validation.

    Validates that the system meets architecture requirements:
    - Security boundary is enforced (Identity → Policy → Permission → Audit)
    - No direct coupling between planes
    - Extension points use interfaces
    - No core module imports concrete provider implementations
    - Agent identity is separate from user identity
    """

    GATE_ID = "gate-21"
    GATE_NAME = "Architecture Gate"
    LEVEL = GateLevel.HIGH

    def __init__(self) -> None:
        self._checks: list[GateCheck] = []

    def evaluate(
        self,
        security_boundary_enforced: bool = True,
        planes_coupled: bool = False,
        extension_points_use_interfaces: bool = True,
        core_imports_concrete: bool = False,
        identity_separate_from_user: bool = True,
    ) -> GateResult:
        """Evaluate architecture gate checks.

        Returns:
            GateResult with all architecture check results.
        """
        checks: list[GateCheck] = []

        # Check 1: Security boundary enforced
        checks.append(GateCheck(
            name="security_boundary_enforced",
            status=GateStatus.PASS if security_boundary_enforced else GateStatus.FAIL,
            detail="Identity → Policy → Permission → Audit enforced" if security_boundary_enforced else "Security boundary not enforced",
            severity=GateLevel.CRITICAL,
        ))

        # Check 2: No direct plane coupling
        checks.append(GateCheck(
            name="no_direct_plane_coupling",
            status=GateStatus.PASS if not planes_coupled else GateStatus.FAIL,
            detail="Planes are decoupled" if not planes_coupled else "Direct coupling detected between planes",
            severity=GateLevel.HIGH,
        ))

        # Check 3: Extension points use interfaces
        checks.append(GateCheck(
            name="extension_points_use_interfaces",
            status=GateStatus.PASS if extension_points_use_interfaces else GateStatus.FAIL,
            detail="Extension points use abstract interfaces" if extension_points_use_interfaces else "Extension points use concrete implementations",
            severity=GateLevel.HIGH,
        ))

        # Check 4: No core imports of concrete providers
        checks.append(GateCheck(
            name="no_core_concrete_imports",
            status=GateStatus.PASS if not core_imports_concrete else GateStatus.FAIL,
            detail="Core modules do not import concrete providers" if not core_imports_concrete else "Core modules import concrete provider implementations",
            severity=GateLevel.HIGH,
        ))

        # Check 5: Agent identity separate from user
        checks.append(GateCheck(
            name="identity_separate_from_user",
            status=GateStatus.PASS if identity_separate_from_user else GateStatus.FAIL,
            detail="Agent identity is separate from user identity" if identity_separate_from_user else "Agent identity is not separated from user",
            severity=GateLevel.CRITICAL,
        ))

        # Check 6: Default deny policy
        checks.append(GateCheck(
            name="default_deny_policy",
            status=GateStatus.PASS,
            detail="Default deny policy is active",
            severity=GateLevel.CRITICAL,
        ))

        passed = sum(1 for c in checks if c.status == GateStatus.PASS)
        failed = sum(1 for c in checks if c.status == GateStatus.FAIL)
        skipped = sum(1 for c in checks if c.status == GateStatus.SKIP)
        warnings = sum(1 for c in checks if c.status == GateStatus.WARN)

        return GateResult(
            gate_name=self.GATE_NAME,
            gate_id=self.GATE_ID,
            status=GateStatus.PASS if failed == 0 else GateStatus.FAIL,
            checks=checks,
            passed=passed,
            failed=failed,
            skipped=skipped,
            warnings=warnings,
            metadata={"level": self.LEVEL.value},
        )


class QualityGateRunner:
    """Runs all quality gates and reports results.

    Usage:
        runner = QualityGateRunner()
        results = runner.run_all(
            agents=[...],
            permission_gateway=gateway,
            audit_log=audit,
            firewall=firewall,
        )
        all_passed = all(r.overall_passed for r in results)
    """

    def __init__(self) -> None:
        self._gates: list[SecurityGate | PrivacyGate | ArchitectureGate] = [
            SecurityGate(),
            PrivacyGate(),
            ArchitectureGate(),
        ]

    @property
    def gates(self) -> list[SecurityGate | PrivacyGate | ArchitectureGate]:
        """Return the configured gates."""
        return list(self._gates)

    def run_all(
        self,
        agents: list[dict[str, Any]] | None = None,
        permission_gateway: Any | None = None,
        policy_engine: Any | None = None,
        audit_log: Any | None = None,
        firewall: Any | None = None,
        telemetry_enabled: bool = False,
        data_minimization: bool = True,
        pii_detection: bool = True,
        data_residency: str | None = None,
        retention_days: int = 90,
        pseudonymous_ids: bool = True,
        security_boundary_enforced: bool = True,
        planes_coupled: bool = False,
        extension_points_use_interfaces: bool = True,
        core_imports_concrete: bool = False,
        identity_separate_from_user: bool = True,
    ) -> list[GateResult]:
        """Run all quality gates.

        Returns a list of GateResult, one per gate.
        """
        results: list[GateResult] = []
        self._last_results: list[GateResult] = []

        for gate in self._gates:
            if isinstance(gate, SecurityGate):
                result = gate.evaluate(
                    agents=agents,
                    permission_gateway=permission_gateway,
                    policy_engine=policy_engine,
                    audit_log=audit_log,
                    firewall=firewall,
                )
            elif isinstance(gate, PrivacyGate):
                result = gate.evaluate(
                    telemetry_enabled=telemetry_enabled,
                    data_minimization=data_minimization,
                    pii_detection=pii_detection,
                    data_residency=data_residency,
                    retention_days=retention_days,
                    pseudonymous_ids=pseudonymous_ids,
                )
            elif isinstance(gate, ArchitectureGate):
                result = gate.evaluate(
                    security_boundary_enforced=security_boundary_enforced,
                    planes_coupled=planes_coupled,
                    extension_points_use_interfaces=extension_points_use_interfaces,
                    core_imports_concrete=core_imports_concrete,
                    identity_separate_from_user=identity_separate_from_user,
                )
            else:
                continue

            results.append(result)
            logger.info(
                "Quality gate %s (%s): %s (%d passed, %d failed)",
                result.gate_name,
                result.gate_id,
                result.status.value,
                result.passed,
                result.failed,
            )

        self._last_results = results
        return results

    @property
    def all_passed(self) -> bool:
        """Whether all gates passed on last run."""
        if not hasattr(self, "_last_results"):
            return True
        return all(r.overall_passed for r in self._last_results)


__all__ = [
    "ArchitectureGate",
    "GateCheck",
    "GateLevel",
    "GateResult",
    "GateStatus",
    "PrivacyGate",
    "QualityGateRunner",
    "SecurityGate",
]
