"""
Agent Replay Candidate Input Builder
====================================

Builds candidate-visible replay inputs from sanitized AWOOOI fixtures.

Candidate Agents must never receive evaluation_labels. This module strips the
answer-key section and emits only incident_context plus minimal source metadata.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any


@dataclass(frozen=True)
class AgentReplayCandidateInput:
    """One candidate-visible incident replay input."""

    run_id: str
    incident_id: str
    schema_version: str = "agent_replay_candidate_input_v1"
    incident_context: dict[str, Any] = field(default_factory=dict)
    source_metadata: dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        return {
            "schema_version": self.schema_version,
            "run_id": self.run_id,
            "incident_id": self.incident_id,
            "incident_context": dict(self.incident_context),
            "source_metadata": dict(self.source_metadata),
        }


def build_candidate_input_from_fixture(
    fixture: dict[str, Any],
) -> AgentReplayCandidateInput:
    """Strip evaluation labels from one replay fixture."""
    required = ("run_id", "incident_id", "incident_context")
    missing = [key for key in required if not fixture.get(key)]
    if missing:
        raise ValueError(f"missing required fixture field(s): {missing}")

    return AgentReplayCandidateInput(
        run_id=str(fixture["run_id"]),
        incident_id=str(fixture["incident_id"]),
        incident_context=dict(fixture["incident_context"]),
        source_metadata=_safe_source_metadata(fixture.get("source_metadata") or {}),
    )


def build_candidate_inputs_from_fixtures(
    fixtures: list[dict[str, Any]],
) -> list[AgentReplayCandidateInput]:
    """Strip evaluation labels from many replay fixtures."""
    return [build_candidate_input_from_fixture(fixture) for fixture in fixtures]


def assert_no_evaluation_label_leak(payload: dict[str, Any]) -> None:
    """Reject candidate-visible payloads that still contain answer-key fields."""
    forbidden = {
        "evaluation_labels",
        "verification_result",
        "execution_success",
        "execution_error",
        "self_healing_score",
        "repair_success",
    }
    leaks = sorted(_find_forbidden_keys(payload, forbidden))
    if leaks:
        raise ValueError(f"candidate input leaks evaluation label field(s): {leaks}")


def _safe_source_metadata(metadata: dict[str, Any]) -> dict[str, Any]:
    allowed = {
        "created_at",
        "updated_at",
        "agent_turn_count",
        "source",
    }
    return {key: value for key, value in metadata.items() if key in allowed}


def _find_forbidden_keys(
    value: Any,
    forbidden: set[str],
    *,
    prefix: str = "",
) -> set[str]:
    found: set[str] = set()
    if isinstance(value, dict):
        for key, nested in value.items():
            key_text = str(key)
            path = f"{prefix}.{key_text}" if prefix else key_text
            if key_text in forbidden:
                found.add(path)
            found.update(_find_forbidden_keys(nested, forbidden, prefix=path))
    elif isinstance(value, list):
        for index, nested in enumerate(value):
            path = f"{prefix}[{index}]"
            found.update(_find_forbidden_keys(nested, forbidden, prefix=path))
    return found
