"""PHI GuardrailEnv — HIPAA PHI access control (RBAC + ABAC composition)."""

from __future__ import annotations

import fnmatch
import time
from typing import Any, Dict, List, Optional

from briefcase.guardrails.framework import (
    BaseGuardrailEnv,
    Effect,
    EvalRequest,
    EvalResult,
    Explanation,
    PolicySpace,
    SpaceBound,
)


class PHIGuardrailEnv(BaseGuardrailEnv):
    """HIPAA PHI guardrail combining RBAC + confidence + tag checks.

    Evaluation order:
    1. RBAC: agent must be in allowed_agents
    2. RBAC: resource must match allowed_resources pattern
    3. ABAC: confidence must meet threshold
    4. ABAC: required_tags must all be present and match in context
    """

    def __init__(
        self,
        allowed_agents: Optional[List[str]] = None,
        allowed_resources: Optional[List[str]] = None,
        confidence_threshold: float = 0.85,
        required_tags: Optional[Dict[str, Any]] = None,
        name: str = "hipaa-phi",
    ):
        allowed_agents = allowed_agents or []
        allowed_resources = allowed_resources or []
        self._name = name
        self._allowed_agents = allowed_agents
        self._allowed_resources = allowed_resources
        self._confidence_threshold = confidence_threshold
        self._required_tags = required_tags or {}
        self._request_space = PolicySpace(
            agents=list(allowed_agents),
            resources=list(allowed_resources),
            context_schema={
                "confidence": SpaceBound(low=0.0, high=1.0),
            },
        )

    def evaluate(self, request: EvalRequest) -> EvalResult:
        """Evaluate HIPAA PHI policy: RBAC + confidence + tags."""
        start = time.monotonic()
        meta: Dict[str, Any] = {
            "agent": request.agent,
            "resource": request.resource,
        }

        # 1. Agent check
        if request.agent not in self._allowed_agents:
            elapsed = (time.monotonic() - start) * 1000.0
            meta["failure"] = "agent_not_allowed"
            return EvalResult(
                effect=Effect.DENY,
                guardrail_name=self.name,
                reason=f"Agent '{request.agent}' not authorized for PHI access",
                eval_time_ms=elapsed,
                metadata=meta,
            )

        # 2. Resource check
        resource_match = any(
            fnmatch.fnmatch(request.resource, pattern)
            for pattern in self._allowed_resources
        )
        if not resource_match:
            elapsed = (time.monotonic() - start) * 1000.0
            meta["failure"] = "resource_not_allowed"
            return EvalResult(
                effect=Effect.DENY,
                guardrail_name=self.name,
                reason=f"Resource '{request.resource}' not in allowed PHI paths",
                eval_time_ms=elapsed,
                metadata=meta,
            )

        # 3. Confidence check
        confidence = request.context.get("confidence", 0.0)
        meta["confidence"] = confidence
        if confidence < self._confidence_threshold:
            elapsed = (time.monotonic() - start) * 1000.0
            meta["failure"] = "confidence_below_threshold"
            return EvalResult(
                effect=Effect.DENY,
                guardrail_name=self.name,
                reason=(
                    f"Confidence {confidence} below threshold "
                    f"{self._confidence_threshold}"
                ),
                eval_time_ms=elapsed,
                metadata=meta,
            )

        # 4. Required tags check
        for tag_key, expected_value in self._required_tags.items():
            actual = request.context.get(tag_key)
            if actual != expected_value:
                elapsed = (time.monotonic() - start) * 1000.0
                meta["failure"] = "tag_mismatch"
                meta["failed_tag"] = tag_key
                meta["expected_tag_value"] = expected_value
                meta["actual_tag_value"] = actual
                return EvalResult(
                    effect=Effect.DENY,
                    guardrail_name=self.name,
                    reason=(
                        f"Required tag '{tag_key}' mismatch: "
                        f"expected {expected_value}, got {actual}"
                    ),
                    eval_time_ms=elapsed,
                    metadata=meta,
                )

        elapsed = (time.monotonic() - start) * 1000.0
        return EvalResult(
            effect=Effect.ALLOW,
            guardrail_name=self.name,
            reason="PHI access granted: all checks passed",
            eval_time_ms=elapsed,
            metadata=meta,
        )

    def explain(self, result: EvalResult) -> Explanation:
        """Produce healthcare-specific explanation."""
        meta = result.metadata
        agent = meta.get("agent", "unknown")
        resource = meta.get("resource", "unknown")
        confidence = meta.get("confidence")
        failure = meta.get("failure")

        extraction = None
        if failure:
            if failure == "confidence_below_threshold":
                extraction = {
                    "attribute": "confidence",
                    "value": confidence,
                    "quote": (
                        f"Agent {agent} requested {resource} "
                        f"with confidence {confidence}"
                    ),
                }
            elif failure == "tag_mismatch":
                tag = meta.get("failed_tag", "unknown")
                extraction = {
                    "attribute": tag,
                    "value": meta.get("actual_tag_value"),
                    "quote": (
                        f"Required tag '{tag}' = {meta.get('expected_tag_value')}, "
                        f"got {meta.get('actual_tag_value')}"
                    ),
                }
            else:
                extraction = {
                    "attribute": failure,
                    "value": None,
                    "quote": result.reason or "",
                }

        policy_applied = {
            "name": "hipaa_phi",
            "condition": (
                f"agent in {self._allowed_agents}, "
                f"confidence >= {self._confidence_threshold}"
            ),
        }

        return Explanation(
            decision_id=result.metadata.get("request_id"),
            effect=result.effect,
            guardrail_name=result.guardrail_name,
            extraction=extraction,
            policy_applied=policy_applied,
            rbac_result={
                "agent": agent,
                "permitted": failure not in ("agent_not_allowed", "resource_not_allowed")
                if failure
                else True,
            },
            abac_result={
                "confidence_check": failure != "confidence_below_threshold"
                if failure
                else True,
                "tag_check": failure != "tag_mismatch" if failure else True,
            },
            eval_time_ms=result.eval_time_ms,
        )
