"""
Agent market watch promotion review
===================================

Reviews watch-only Agent candidates for the next governance step. This service
does not approve replay, SDK installation, paid API calls, shadow/canary, or
production routing. It can only say whether a watched candidate has enough
primary-source monitoring evidence to enter a future market scorecard prescreen.
"""

from __future__ import annotations

from datetime import datetime, timezone
from typing import Any


def run_agent_market_watch_promotion_review(
    *,
    watch_report: dict[str, Any],
    integration_review: dict[str, Any],
    discovery_classification: dict[str, Any],
    candidate_registry: dict[str, Any],
    generated_at: str | None = None,
) -> dict[str, Any]:
    """Build a no-approval review for watch-only candidate priority upgrades."""
    if watch_report.get("schema_version") != "agent_market_watch_report_v1":
        raise ValueError("watch_report must be agent_market_watch_report_v1")
    if integration_review.get("schema_version") != "agent_market_integration_review_v1":
        raise ValueError("integration_review must be agent_market_integration_review_v1")
    if discovery_classification.get("schema_version") != (
        "agent_market_discovery_classification_v1"
    ):
        raise ValueError(
            "discovery_classification must be agent_market_discovery_classification_v1"
        )

    watch_by_id = {
        str(candidate.get("candidate_id")): candidate
        for candidate in watch_report.get("candidates") or []
        if candidate.get("candidate_id")
    }
    integration_by_id = {
        str(review.get("candidate_id")): review
        for review in integration_review.get("reviews") or []
        if review.get("candidate_id")
    }
    classification_by_repo = {
        str(candidate.get("repository_full_name", "")): candidate
        for candidate in discovery_classification.get("candidates") or []
        if candidate.get("repository_full_name")
    }

    reviews = [
        _review_watch_only_candidate(
            registry_candidate=candidate,
            watch_candidate=watch_by_id.get(str(candidate.get("candidate_id")), {}),
            integration_candidate=integration_by_id.get(str(candidate.get("candidate_id")), {}),
            classification_by_repo=classification_by_repo,
        )
        for candidate in candidate_registry.get("candidates") or []
        if _is_watch_only(candidate)
    ]

    return {
        "schema_version": "agent_market_watch_promotion_review_v1",
        "generated_at": generated_at or datetime.now(timezone.utc).isoformat(),  # noqa: UP017
        "inputs": {
            "watch_report_generated_at": watch_report.get("generated_at"),
            "integration_review_generated_at": integration_review.get("generated_at"),
            "discovery_classification_generated_at": discovery_classification.get("generated_at"),
            "candidate_registry_schema_version": str(candidate_registry.get("schema_version", "")),
        },
        "policy": {
            "priority_upgrade_approved": False,
            "market_scorecard_update_approved": False,
            "replay_candidate_approved": False,
            "sdk_installation_approved": False,
            "paid_api_calls_approved": False,
            "production_changes_approved": False,
            "shadow_or_canary_approved": False,
            "replacement_decision_allowed": False,
        },
        "summary": _summary(reviews),
        "reviews": reviews,
    }


def _review_watch_only_candidate(
    *,
    registry_candidate: dict[str, Any],
    watch_candidate: dict[str, Any],
    integration_candidate: dict[str, Any],
    classification_by_repo: dict[str, dict[str, Any]],
) -> dict[str, Any]:
    candidate_id = str(registry_candidate.get("candidate_id", ""))
    classification = _matching_classification(registry_candidate, classification_by_repo)
    source_results = list(watch_candidate.get("sources") or [])
    source_failures = [source for source in source_results if source.get("error")]
    has_release_version = any(source.get("version") for source in source_results)
    source_count = len(source_results)
    integration_stage = str((integration_candidate.get("readiness") or {}).get("stage") or "")
    classification_recommended = bool(classification.get("watch_addition_recommended", False))

    eligible_for_scorecard = (
        source_count >= 2
        and not source_failures
        and has_release_version
        and integration_stage == "watch_only_primary_source_monitoring"
        and classification_recommended
    )
    decision = (
        "eligible_for_operator_priority_review_before_market_scorecard"
        if eligible_for_scorecard
        else "remain_watch_only_until_evidence_gap_resolved"
    )
    blockers = _blockers(
        source_count=source_count,
        source_failures=source_failures,
        has_release_version=has_release_version,
        integration_stage=integration_stage,
        classification_recommended=classification_recommended,
    )
    return {
        "candidate_id": candidate_id,
        "display_name": str(registry_candidate.get("display_name") or candidate_id),
        "role": registry_candidate.get("role"),
        "official_url": registry_candidate.get("official_url"),
        "source_count": source_count,
        "source_failures": len(source_failures),
        "release_version_observed": has_release_version,
        "latest_versions": [
            source.get("version") for source in source_results if source.get("version")
        ],
        "integration_stage": integration_stage,
        "classification": {
            "repository_full_name": classification.get("repository_full_name"),
            "classification": classification.get("classification"),
            "recommendation": classification.get("recommendation"),
            "watch_addition_recommended": classification_recommended,
            "risk_flags": list(classification.get("risk_flags") or []),
        },
        "decision": decision,
        "eligible_for_market_scorecard_prescreen": eligible_for_scorecard,
        "approved_for_replay": False,
        "approved_for_sdk_install": False,
        "approved_for_paid_api_calls": False,
        "approved_for_shadow_or_canary": False,
        "blockers": blockers,
        "required_next_gate": (
            "operator_priority_upgrade_then_market_scorecard_prescreen"
            if eligible_for_scorecard
            else "continue_watch_only_until_primary_source_evidence_is_sufficient"
        ),
    }


def _matching_classification(
    registry_candidate: dict[str, Any],
    classification_by_repo: dict[str, dict[str, Any]],
) -> dict[str, Any]:
    official_url = str(registry_candidate.get("official_url") or "").lower()
    source_repository = str(registry_candidate.get("source_repository") or "").lower()
    if source_repository and source_repository in classification_by_repo:
        return classification_by_repo[source_repository]
    for repo, classification in classification_by_repo.items():
        if repo and repo in official_url:
            return classification
        html_url = str(classification.get("html_url") or "").lower()
        homepage = str(classification.get("homepage") or "").lower()
        if official_url and (official_url == html_url or official_url == homepage):
            return classification
    return {}


def _blockers(
    *,
    source_count: int,
    source_failures: list[dict[str, Any]],
    has_release_version: bool,
    integration_stage: str,
    classification_recommended: bool,
) -> list[str]:
    blockers = []
    if source_count < 2:
        blockers.append("needs_at_least_two_primary_sources")
    if source_failures:
        blockers.append("source_failures_must_be_zero")
    if not has_release_version:
        blockers.append("needs_versioned_release_source")
    if integration_stage != "watch_only_primary_source_monitoring":
        blockers.append("integration_review_must_confirm_watch_only_stage")
    if not classification_recommended:
        blockers.append("discovery_classification_must_recommend_watch_addition")
    return blockers


def _is_watch_only(candidate: dict[str, Any]) -> bool:
    return (
        candidate.get("evaluation_priority") == "watch_only"
        or candidate.get("required_stage") == "watch_only_primary_source_monitoring"
    )


def _summary(reviews: list[dict[str, Any]]) -> dict[str, int]:
    return {
        "watch_only_candidates_reviewed": len(reviews),
        "eligible_for_market_scorecard_prescreen": sum(
            1 for review in reviews if review["eligible_for_market_scorecard_prescreen"]
        ),
        "remain_watch_only": sum(
            1 for review in reviews if not review["eligible_for_market_scorecard_prescreen"]
        ),
        "priority_upgrades_approved": 0,
        "market_scorecard_updates_approved": 0,
        "replay_candidates_approved": 0,
        "sdk_installations_approved": 0,
        "paid_api_calls_approved": 0,
        "production_changes_approved": 0,
        "shadow_or_canary_approved": 0,
    }
