"""Seed migration helpers for the inference registry.

Provides canonical endpoint profiles, model deployments, and agent
provider-to-stage-binding conversion logic for migrating from the legacy
model_provider/model_name fields to the v3 registry.

Task 18.1-18.5: Migrate existing provider records.
Requirements: 3.8, 3.9
"""
from __future__ import annotations

from typing import Any
from uuid import UUID

# ─── Well-known IDs ────────────────────────────────────────────────────────────
# These match the SQL seed migration (042_seed_inference_registry.sql)

OLLAMA_ENDPOINT_ID = UUID("a0000000-0000-4000-8000-000000000001")
VLLM_ENDPOINT_ID = UUID("a0000000-0000-4000-8000-000000000002")
OLLAMA_DEPLOYMENT_ID = UUID("b0000000-0000-4000-8000-000000000001")
VLLM_DEPLOYMENT_ID = UUID("b0000000-0000-4000-8000-000000000002")


def get_initial_endpoints() -> list[dict[str, Any]]:
    """Return the canonical endpoint profiles for the seed migration.

    Returns:
        List of endpoint dicts matching the inference_endpoints table schema.
        - stonks-ollama: Ollama native protocol at cluster-internal URL.
        - stonks-vllm: OpenAI-chat protocol (vLLM) at cluster-internal URL.
    """
    return [
        {
            "id": OLLAMA_ENDPOINT_ID,
            "name": "stonks-ollama",
            "protocol": "ollama_native",
            "base_url": "http://ollama.ollama-service.svc.cluster.local:11434",
            "auth_secret_ref": None,
            "auth_scheme": "none",
            "default_headers": {},
            "health_path": "/api/tags",
            "enabled": True,
        },
        {
            "id": VLLM_ENDPOINT_ID,
            "name": "stonks-vllm",
            "protocol": "openai_chat",
            "base_url": "http://kube-vllm.stonks-oracle.svc.cluster.local:8000",
            "auth_secret_ref": None,
            "auth_scheme": "none",
            "default_headers": {},
            "health_path": "/health",
            "enabled": True,
        },
    ]


def get_initial_deployments() -> list[dict[str, Any]]:
    """Return the initial model deployments for the seed migration.

    Returns:
        List of deployment dicts matching the model_deployments table schema.
        - Ollama: qwen3.5:9b with native JSON mode.
        - vLLM: AxionML/Qwen3.5-9B-NVFP4 on RTX 4070 Ti SUPER, strict JSON Schema.
    """
    return [
        {
            "id": OLLAMA_DEPLOYMENT_ID,
            "endpoint_id": OLLAMA_ENDPOINT_ID,
            "served_model_name": "qwen3.5:9b",
            "display_name": "Qwen 3.5 9B (Ollama)",
            "capabilities": {
                "chat_completions": True,
                "json_schema": False,
                "json_object": True,
                "seed": False,
                "usage": False,
                "max_completion_tokens": False,
                "model_listing": True,
            },
            "context_window": 32768,
            "max_output_tokens": 32768,
            "quantization": None,
            "runtime_metadata": {
                "source": "ollama_native",
                "notes": "Ollama-served model with native JSON mode",
            },
            "enabled": True,
        },
        {
            "id": VLLM_DEPLOYMENT_ID,
            "endpoint_id": VLLM_ENDPOINT_ID,
            "served_model_name": "AxionML/Qwen3.5-9B-NVFP4",
            "display_name": "Qwen 3.5 9B NVFP4 (vLLM)",
            "capabilities": {
                "chat_completions": True,
                "json_schema": True,
                "json_object": True,
                "seed": True,
                "usage": True,
                "max_completion_tokens": True,
                "model_listing": True,
            },
            "context_window": 8192,
            "max_output_tokens": 2048,
            "quantization": "NVFP4",
            "runtime_metadata": {
                "gpu": "RTX 4070 Ti SUPER",
                "gpu_memory_utilization": 0.80,
                "max_num_seqs": 8,
                "vllm_structured_outputs": True,
            },
            "enabled": True,
        },
    ]


# ─── Provider mapping ──────────────────────────────────────────────────────────
# Maps legacy model_provider values to endpoint/deployment IDs.

_PROVIDER_TO_ENDPOINT: dict[str, UUID] = {
    "ollama": OLLAMA_ENDPOINT_ID,
    "vllm": VLLM_ENDPOINT_ID,
}

_PROVIDER_TO_DEPLOYMENT: dict[str, UUID] = {
    "ollama": OLLAMA_DEPLOYMENT_ID,
    "vllm": VLLM_DEPLOYMENT_ID,
}


class UnknownProviderError(ValueError):
    """Raised when an agent record has an unrecognized model_provider value."""

    def __init__(self, provider: str, agent_id: str) -> None:
        self.provider = provider
        self.agent_id = agent_id
        super().__init__(
            f"Unknown model_provider '{provider}' for agent '{agent_id}'. "
            f"Supported providers: {sorted(_PROVIDER_TO_ENDPOINT.keys())}. "
            f"Cannot silently convert unknown providers."
        )


def convert_agent_providers(agent_records: list[dict[str, Any]]) -> list[dict[str, Any]]:
    """Convert existing agent model_provider/model_name fields to stage bindings.

    For each agent record with a known model_provider (ollama or vllm), produces
    a stage binding record that maps the agent to the appropriate endpoint and
    model deployment. The original model_provider and model_name fields are
    retained for backward compatibility — this function supplements, not replaces.

    Args:
        agent_records: List of dicts with at least 'id' (or 'agent_id'),
            'model_provider', and optionally 'slug' fields.

    Returns:
        List of stage binding dicts suitable for insertion into
        agent_stage_bindings.

    Raises:
        UnknownProviderError: If a record has a model_provider that cannot be
            mapped. Unknown providers must NOT be silently converted.
    """
    bindings: list[dict[str, Any]] = []

    for record in agent_records:
        agent_id = str(record.get("id") or record.get("agent_id", ""))
        provider = (record.get("model_provider") or "").strip().lower()

        if not provider:
            # No provider set — skip, nothing to convert
            continue

        if provider not in _PROVIDER_TO_ENDPOINT:
            raise UnknownProviderError(provider=provider, agent_id=agent_id)

        endpoint_id = _PROVIDER_TO_ENDPOINT[provider]
        deployment_id = _PROVIDER_TO_DEPLOYMENT[provider]

        # Determine stage from agent slug or default to 'extraction'
        slug = record.get("slug", "")
        stage = _infer_stage_from_slug(slug)

        bindings.append({
            "agent_id": agent_id,
            "stage": stage,
            "endpoint_id": endpoint_id,
            "model_deployment_id": str(deployment_id),
            "route_order": 0,
            "routing_config": {},
            "is_active": True,
        })

    return bindings


def _infer_stage_from_slug(slug: str) -> str:
    """Map an agent slug to a pipeline stage name.

    Known agent slugs and their corresponding stages:
        - document-extractor -> extraction
        - event-classifier -> classification
        - thesis-rewriter -> thesis_rewrite
        - report-summarizer -> summarization

    Falls back to 'extraction' for unrecognized slugs.
    """
    slug_to_stage: dict[str, str] = {
        "document-extractor": "extraction",
        "event-classifier": "classification",
        "thesis-rewriter": "thesis_rewrite",
        "report-summarizer": "summarization",
    }
    return slug_to_stage.get(slug, "extraction")


# ─── Conflicting defaults identification ──────────────────────────────────────

# Known locations where model/provider defaults have historically conflicted.
_KNOWN_CONFLICT_LOCATIONS: list[dict[str, str]] = [
    {
        "location": "services/shared/config.py",
        "field": "VLLMConfig.model",
        "description": "Python config default for vLLM model name",
    },
    {
        "location": "services/shared/config.py",
        "field": "VLLMConfig.base_url",
        "description": "Python config default for vLLM base URL (192.168.42.254:8000)",
    },
    {
        "location": "infra/migrations/026_ai_agents.sql",
        "field": "model_provider/model_name DEFAULT",
        "description": "Agent table DDL defaults to 'ollama'/'qwen3.5:9b-fast'",
    },
    {
        "location": "infra/migrations/031_fix_agent_defaults.sql",
        "field": "model_provider UPDATE",
        "description": "Migration updates agents to 'vllm'/'AxionML/Qwen3.5-9B-NVFP4'",
    },
    {
        "location": "infra/migrations/033_stop_hardcoding_agent_model.sql",
        "field": "model_provider UPDATE",
        "description": "Migration updates agents to 'vllm'/'AxionML/Qwen3.5-9B-NVFP4'",
    },
    {
        "location": "infra/helm/stonks-oracle/values.yaml",
        "field": "VLLM_BASE_URL / VLLM_MODEL",
        "description": "Helm values point to nuextract-external.vllm-service with NuExtract3",
    },
    {
        "location": "infra/helm/stonks-oracle/values.yaml",
        "field": "OLLAMA_BASE_URL / OLLAMA_MODEL",
        "description": "Helm values point to nuextract-external.vllm-service with NuExtract3",
    },
    {
        "location": "infra/kube-vllm/deployment.yaml",
        "field": "vLLM deployment model arg",
        "description": "Standalone kube-vllm deployment with AxionML/Qwen3.5-9B-NVFP4",
    },
]


def identify_conflicting_defaults() -> list[str]:
    """List locations where model defaults historically conflict.

    Returns a list of human-readable strings identifying places where
    the model provider, model name, or base URL have conflicting
    defaults across config.py, migrations, Helm values, and the
    kube-vllm deployment.

    These conflicts should be resolved after the inference registry
    is established as the single source of truth.

    Returns:
        List of conflict description strings.
    """
    conflicts: list[str] = []

    for entry in _KNOWN_CONFLICT_LOCATIONS:
        conflicts.append(
            f"{entry['location']} [{entry['field']}]: {entry['description']}"
        )

    return conflicts
