"""Pipeline adapter — bridges GuardrailPipeline to GuardrailEnv protocol."""

from __future__ import annotations

from typing import Any, Dict, List, Optional

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


class PipelineAdapter(BaseGuardrailEnv):
    """Adapt a GuardrailPipeline to the GuardrailEnv interface.

    GuardrailPipeline.evaluate() returns PipelineResult (has final_effect),
    not EvalResult (has effect). This adapter bridges the gap, allowing
    pipelines to be used wherever a GuardrailEnv is expected — including
    GuardrailBenchmark, VectorGuardrailEnv, and nested pipelines.

    Usage:
        pipeline = GuardrailPipeline([rbac_env, abac_env])
        adapted = PipelineAdapter(pipeline)
        result = adapted.evaluate(request)  # returns EvalResult
    """

    def __init__(self, pipeline: GuardrailPipeline, name: Optional[str] = None):
        self._pipeline = pipeline
        self._name = name or pipeline.name

    @property
    def request_space(self) -> PolicySpace:
        """Computed as union of all stage request spaces."""
        stages = self._pipeline.stages
        if not stages:
            return PolicySpace()
        space = stages[0].request_space
        for stage in stages[1:]:
            space = SpaceAlgebra.union(space, stage.request_space)
        return space

    def evaluate(self, request: EvalRequest) -> EvalResult:
        """Evaluate via pipeline, map PipelineResult to EvalResult."""
        pipeline_result = self._pipeline.evaluate(request)
        return EvalResult(
            effect=pipeline_result.final_effect,
            guardrail_name=self._name,
            reason=self._build_reason(pipeline_result),
            eval_time_ms=pipeline_result.eval_time_ms,
            metadata={
                "short_circuited": pipeline_result.short_circuited,
                "individual_results_count": len(pipeline_result.individual_results),
            },
        )

    def _build_reason(self, pipeline_result) -> str:
        if pipeline_result.final_effect == Effect.DENY:
            deny_reasons = [
                r.reason for r in pipeline_result.individual_results
                if r.effect == Effect.DENY and r.reason
            ]
            if deny_reasons:
                return f"Pipeline denied: {deny_reasons[0]}"
            return "Pipeline denied"
        return "Pipeline allowed: all stages passed"

    def explain(self, result: EvalResult) -> Explanation:
        """Assemble explanation from pipeline metadata."""
        return Explanation(
            decision_id=result.metadata.get("request_id"),
            effect=result.effect,
            guardrail_name=result.guardrail_name,
            policy_applied={
                "name": "pipeline",
                "stages": len(self._pipeline.stages),
                "short_circuited": result.metadata.get("short_circuited"),
            },
            eval_time_ms=result.eval_time_ms,
        )
