"""
AI technology watch service.

Builds a read-only cross-domain AI technology radar from primary sources. This
wraps the existing market-watch fetcher so the broader radar uses the same
no-SDK, no-paid-API, no-production-change boundary as the Agent market watch.
"""

from __future__ import annotations

import importlib.util
import sys
from collections import Counter
from collections.abc import Callable
from datetime import datetime, timezone
from pathlib import Path
from typing import Any

FetchSource = Callable[[str, int], Any]

_AGENT_MARKET_WATCH_MODULE = None


def run_ai_technology_watch(
    registry: dict[str, Any],
    *,
    registry_path: str,
    mode: str = "live",
    previous_report: dict[str, Any] | None = None,
    timeout_seconds: int = 12,
    fetcher: FetchSource | None = None,
    generated_at: str | None = None,
) -> dict[str, Any]:
    """Build a broad read-only AI technology watch report."""
    run_agent_market_watch = _load_agent_market_watch_runner()
    agent_previous = _to_agent_previous_report(previous_report or {})
    raw_report = run_agent_market_watch(
        registry,
        registry_path=registry_path,
        mode=mode,
        previous_report=agent_previous,
        timeout_seconds=timeout_seconds,
        fetcher=fetcher,
        generated_at=generated_at,
    )
    registry_by_id = {
        str(item.get("candidate_id", "")).strip(): item
        for item in registry.get("candidates") or []
        if str(item.get("candidate_id", "")).strip()
    }
    technologies = [
        _technology_row(raw_candidate, registry_by_id.get(raw_candidate["candidate_id"], {}))
        for raw_candidate in raw_report.get("candidates") or []
    ]
    area_counts = Counter(row["technology_area"] for row in technologies)
    priority_counts = Counter(row["evaluation_priority"] for row in technologies)
    changed = [row for row in technologies if row["changed"]]

    return {
        "schema_version": "ai_technology_watch_report_v1",
        "generated_at": generated_at or datetime.now(timezone.utc).isoformat(),
        "mode": mode,
        "registry": {
            "path": registry_path,
            "schema_version": str(registry.get("schema_version", "")),
            "updated_at": str(registry.get("updated_at", "")),
        },
        "cadence": dict(registry.get("cadence") or {}),
        "policy": _policy(registry),
        "summary": {
            "technology_count": len(technologies),
            "technology_area_count": len(area_counts),
            "source_count": raw_report["summary"]["source_count"],
            "changed_technologies": len(changed),
            "watch_only_technologies": len(technologies) - len(changed),
            "review_queue_count": len(changed),
            "source_failure_count": raw_report["summary"]["failure_count"],
            "high_priority_count": priority_counts.get("p0", 0)
            + priority_counts.get("p1", 0),
        },
        "technology_area_counts": dict(sorted(area_counts.items())),
        "technologies": technologies,
        "review_queue": [_review_queue_item(row) for row in changed],
        "new_technology_discovery": raw_report.get("new_candidate_discovery") or [],
        "failures": raw_report.get("failures") or [],
    }


def _load_agent_market_watch_runner() -> Any:
    global _AGENT_MARKET_WATCH_MODULE
    if _AGENT_MARKET_WATCH_MODULE is not None:
        return _AGENT_MARKET_WATCH_MODULE.run_agent_market_watch

    module_name = "awoooi_agent_market_watch_service_for_ai_technology"
    service_path = Path(__file__).with_name("agent_market_watch.py")
    spec = importlib.util.spec_from_file_location(module_name, service_path)
    if spec is None or spec.loader is None:
        raise RuntimeError(f"cannot load agent market watch service from {service_path}")
    module = importlib.util.module_from_spec(spec)
    sys.modules[module_name] = module
    spec.loader.exec_module(module)
    _AGENT_MARKET_WATCH_MODULE = module
    return module.run_agent_market_watch


def _policy(registry: dict[str, Any]) -> dict[str, Any]:
    policy = dict(registry.get("policy") or {})
    policy.setdefault("read_only", True)
    policy.setdefault("sdk_installation_approved", False)
    policy.setdefault("paid_api_calls_approved", False)
    policy.setdefault("production_routing_approved", False)
    policy.setdefault("workflow_modification_approved", False)
    policy.setdefault("telegram_send_approved", False)
    policy.setdefault("model_provider_switch_approved", False)
    policy.setdefault("host_write_approved", False)
    return policy


def _technology_row(raw_candidate: dict[str, Any], registry_candidate: dict[str, Any]) -> dict[str, Any]:
    return {
        "technology_id": raw_candidate["candidate_id"],
        "display_name": raw_candidate["display_name"],
        "technology_area": str(registry_candidate.get("technology_area") or "uncategorized"),
        "integration_surface": str(registry_candidate.get("integration_surface") or "watch_only"),
        "awoooi_role": str(registry_candidate.get("awoooi_role") or raw_candidate.get("recommended_role") or ""),
        "evaluation_priority": raw_candidate.get("evaluation_priority") or "watch",
        "requires_cost_approval": bool(raw_candidate.get("requires_cost_approval")),
        "requires_dependency_approval": bool(raw_candidate.get("requires_dependency_approval")),
        "requires_security_review": bool(registry_candidate.get("requires_security_review", True)),
        "sources": raw_candidate.get("sources") or [],
        "changed": bool(raw_candidate.get("changed")),
        "decision": raw_candidate.get("decision"),
        "recommended_actions": _recommended_actions(raw_candidate, registry_candidate),
    }


def _recommended_actions(
    raw_candidate: dict[str, Any],
    registry_candidate: dict[str, Any],
) -> list[str]:
    if raw_candidate.get("changed"):
        return [
            "refresh_ai_technology_scorecard",
            "classify_business_applicability",
            "prepare_no_install_integration_note",
            "route_high_risk_items_to_human_review",
        ]
    if any(source.get("error") for source in raw_candidate.get("sources") or []):
        return ["retry_primary_source_fetch", "keep_current_runtime_status"]
    actions = list(registry_candidate.get("steady_state_actions") or [])
    return actions or ["keep_watch_only_status"]


def _review_queue_item(row: dict[str, Any]) -> dict[str, Any]:
    return {
        "technology_id": row["technology_id"],
        "technology_area": row["technology_area"],
        "reason": "primary_source_version_or_content_changed",
        "required_next_gate": "scorecard_then_sandbox_or_replay_plan",
        "requires_cost_approval": row["requires_cost_approval"],
        "requires_dependency_approval": row["requires_dependency_approval"],
        "requires_security_review": row["requires_security_review"],
    }


def _to_agent_previous_report(report: dict[str, Any]) -> dict[str, Any] | None:
    if not report:
        return None
    if report.get("schema_version") == "agent_market_watch_report_v1":
        return report
    if report.get("schema_version") != "ai_technology_watch_report_v1":
        return None
    return {
        "schema_version": "agent_market_watch_report_v1",
        "candidates": [
            {
                "candidate_id": row.get("technology_id"),
                "sources": row.get("sources") or [],
            }
            for row in report.get("technologies") or []
            if row.get("technology_id")
        ],
    }
