"""
Agent Market Capability Scorecard
=================================

Scores market Agent framework evidence before AWOOOI incident replay.

This is a prescreen only. A candidate can outrank OpenClaw here and still be
blocked from production until it passes the replay/shadow/canary gates.
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any

MAX_CAPABILITY_SCORE = 3


@dataclass(frozen=True)
class MarketCapabilityScorecard:
    candidate_id: str
    display_name: str
    total_score: float
    rank: int
    beats_baseline_capability: bool | None
    replay_priority: str
    strengths: list[str]
    gaps: list[str]
    capabilities: dict[str, int]
    official_sources: list[dict[str, str]]
    risks: list[str]

    def to_dict(self) -> dict[str, Any]:
        return {
            "candidate_id": self.candidate_id,
            "display_name": self.display_name,
            "rank": self.rank,
            "total_score": self.total_score,
            "beats_baseline_capability": self.beats_baseline_capability,
            "replay_priority": self.replay_priority,
            "strengths": list(self.strengths),
            "gaps": list(self.gaps),
            "capabilities": dict(self.capabilities),
            "official_sources": list(self.official_sources),
            "risks": list(self.risks),
        }


@dataclass(frozen=True)
class MarketCapabilityReport:
    baseline_candidate_id: str
    scoring_version: str
    dimensions: dict[str, float]
    candidates: list[MarketCapabilityScorecard]

    def to_dict(self) -> dict[str, Any]:
        return {
            "schema_version": "agent_market_capability_scorecard_v1",
            "baseline_candidate_id": self.baseline_candidate_id,
            "scoring_version": self.scoring_version,
            "dimensions": dict(self.dimensions),
            "candidates": [candidate.to_dict() for candidate in self.candidates],
            "candidates_above_baseline": [
                candidate.candidate_id
                for candidate in self.candidates
                if candidate.beats_baseline_capability is True
            ],
        }


def score_market_capabilities(payload: dict[str, Any]) -> MarketCapabilityReport:
    """Score official market evidence with a shared weighted rubric."""
    baseline_candidate_id = str(payload.get("baseline_candidate_id", "openclaw_incumbent"))
    scoring_version = str(payload.get("scoring_version", "market_capability_v1"))
    dimensions = _dimension_weights(payload)
    candidates = payload.get("candidates") or []
    if not candidates:
        raise ValueError("market evidence must include at least one candidate")

    raw_scorecards = [
        _score_candidate(candidate, dimensions)
        for candidate in candidates
    ]
    baseline = next(
        (
            scorecard
            for scorecard in raw_scorecards
            if scorecard.candidate_id == baseline_candidate_id
        ),
        None,
    )
    baseline_score = baseline.total_score if baseline else None

    sorted_scorecards = sorted(
        raw_scorecards,
        key=lambda scorecard: (-scorecard.total_score, scorecard.candidate_id),
    )
    final: list[MarketCapabilityScorecard] = []
    for index, scorecard in enumerate(sorted_scorecards, start=1):
        beats_baseline: bool | None
        if scorecard.candidate_id == baseline_candidate_id or baseline_score is None:
            beats_baseline = None
        else:
            beats_baseline = scorecard.total_score > baseline_score
        replay_priority = _replay_priority(
            candidate_id=scorecard.candidate_id,
            declared_priority=scorecard.replay_priority,
            beats_baseline=beats_baseline,
        )
        final.append(
            MarketCapabilityScorecard(
                candidate_id=scorecard.candidate_id,
                display_name=scorecard.display_name,
                total_score=scorecard.total_score,
                rank=index,
                beats_baseline_capability=beats_baseline,
                replay_priority=replay_priority,
                strengths=scorecard.strengths,
                gaps=scorecard.gaps,
                capabilities=scorecard.capabilities,
                official_sources=scorecard.official_sources,
                risks=scorecard.risks,
            )
        )

    return MarketCapabilityReport(
        baseline_candidate_id=baseline_candidate_id,
        scoring_version=scoring_version,
        dimensions=dimensions,
        candidates=final,
    )


def _dimension_weights(payload: dict[str, Any]) -> dict[str, float]:
    dimensions = payload.get("dimensions") or {}
    if not dimensions:
        raise ValueError("market evidence must include weighted dimensions")
    weights = {str(key): float(value) for key, value in dimensions.items()}
    total = round(sum(weights.values()), 6)
    if total != 1.0:
        raise ValueError(f"dimension weights must sum to 1.0, got {total}")
    return weights


def _score_candidate(
    candidate: dict[str, Any],
    dimensions: dict[str, float],
) -> MarketCapabilityScorecard:
    candidate_id = str(candidate.get("candidate_id", "")).strip()
    display_name = str(candidate.get("display_name", candidate_id)).strip()
    if not candidate_id:
        raise ValueError("candidate_id is required")

    capabilities = {
        str(key): int(value)
        for key, value in (candidate.get("capabilities") or {}).items()
    }
    missing = [dimension for dimension in dimensions if dimension not in capabilities]
    if missing:
        raise ValueError(f"{candidate_id}: missing capability dimensions: {missing}")
    invalid = {
        key: value
        for key, value in capabilities.items()
        if value < 0 or value > MAX_CAPABILITY_SCORE
    }
    if invalid:
        raise ValueError(f"{candidate_id}: capability scores must be 0..3: {invalid}")

    total_score = sum(
        (capabilities[dimension] / MAX_CAPABILITY_SCORE) * weight
        for dimension, weight in dimensions.items()
    )

    return MarketCapabilityScorecard(
        candidate_id=candidate_id,
        display_name=display_name,
        total_score=round(total_score, 4),
        rank=0,
        beats_baseline_capability=None,
        replay_priority=str(candidate.get("evaluation_priority", "can_test")),
        strengths=[
            dimension
            for dimension in dimensions
            if capabilities[dimension] == MAX_CAPABILITY_SCORE
        ],
        gaps=[
            dimension
            for dimension in dimensions
            if capabilities[dimension] <= 1
        ],
        capabilities=capabilities,
        official_sources=list(candidate.get("official_sources") or []),
        risks=list(candidate.get("risks") or []),
    )


def _replay_priority(
    *,
    candidate_id: str,
    declared_priority: str,
    beats_baseline: bool | None,
) -> str:
    if candidate_id == "openclaw_incumbent":
        return "baseline"
    if declared_priority == "must_test" and beats_baseline:
        return "p0_replay"
    if beats_baseline:
        return "p1_replay"
    return "watch"
