"""Policy enforcer — applies zero-tolerance/warn rules, determines exit code."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any

from apiposture_pro.enterprise.policy.policy_loader import SEVERITY_ORDER, PolicyConfig


@dataclass
class PolicyResult:
    """Result of policy enforcement check."""

    should_fail: bool
    zero_tolerance_violations: list[str] = field(default_factory=list)  # rule IDs fired
    severity_threshold_violations: list[dict[str, Any]] = field(default_factory=list)
    warnings: list[str] = field(default_factory=list)  # rule IDs that matched warn list


def enforce_policy(
    policy: PolicyConfig,
    findings: list[dict[str, Any]],
) -> PolicyResult:
    """
    Apply policy to a list of findings.

    A finding dict must have at minimum:
        rule_id  : str
        severity : str (critical|high|medium|low|info)

    Exit code 1 if:
        - any zero_tolerance rule ID appears in findings, OR
        - any finding severity >= fail_on threshold
    """
    zero_tolerance_violations: list[str] = []
    severity_threshold_violations: list[dict[str, Any]] = []
    warnings: list[str] = []

    fail_on_index = SEVERITY_ORDER.index(policy.fail_on) if policy.fail_on in SEVERITY_ORDER else 1

    for finding in findings:
        rule_id = finding.get("rule_id", "")
        severity = finding.get("severity", "info").lower()

        # Zero-tolerance check
        if rule_id in policy.zero_tolerance:
            if rule_id not in zero_tolerance_violations:
                zero_tolerance_violations.append(rule_id)

        # Warn check
        if rule_id in policy.warn:
            if rule_id not in warnings:
                warnings.append(rule_id)

        # Severity threshold check
        sev_index = SEVERITY_ORDER.index(severity) if severity in SEVERITY_ORDER else len(SEVERITY_ORDER)
        if sev_index <= fail_on_index:
            severity_threshold_violations.append(finding)

    should_fail = bool(zero_tolerance_violations) or bool(severity_threshold_violations)

    return PolicyResult(
        should_fail=should_fail,
        zero_tolerance_violations=zero_tolerance_violations,
        severity_threshold_violations=severity_threshold_violations,
        warnings=warnings,
    )
