"""Wizard API router — agent CRUD, model catalog, activation."""

from __future__ import annotations

import asyncio
import logging
from datetime import datetime, timezone

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel

from roohai.agents import list_agents, get_agent, save_agent, delete_agent, validate_agent_name
from roohai.registry import registry
from roohai.secrets import set_agent_secrets, get_agent_secrets, delete_agent_secrets

logger = logging.getLogger(__name__)

router = APIRouter()


class CreateAgentRequest(BaseModel):
    name: str
    pipeline: dict
    models: dict
    secrets: dict | None = None
    system_prompt: str
    transport: str = "websocket"
    llm_streaming: bool = True


# --- Catalog ---


@router.get("/api/catalog")
async def catalog():
    """Return the full model catalog from registry."""
    from roohai.pipeline import register_all_models
    register_all_models()
    return {"catalog": registry.catalog()}


# --- Agent CRUD ---


@router.get("/api/agents")
async def api_list_agents():
    return {"agents": list_agents()}


@router.post("/api/agents")
async def api_create_agent(req: CreateAgentRequest):
    # Validate name
    try:
        validate_agent_name(req.name)
    except ValueError as exc:
        raise HTTPException(status_code=400, detail=str(exc))

    # Check for duplicates
    if get_agent(req.name):
        raise HTTPException(status_code=409, detail=f"Agent '{req.name}' already exists")

    config = {
        "name": req.name,
        "created_at": datetime.now(timezone.utc).isoformat(),
        "status": "created",
        "pipeline": req.pipeline,
        "models": req.models,
        "system_prompt": req.system_prompt,
        "transport": req.transport,
        "llm_streaming": req.llm_streaming,
    }

    save_agent(config)

    # Store secrets separately (never in agent yaml)
    if req.secrets:
        set_agent_secrets(req.name, req.secrets)

    return {"status": "created", "agent": config}


@router.get("/api/agents/{name}")
async def api_get_agent(name: str):
    agent = get_agent(name)
    if not agent:
        raise HTTPException(status_code=404, detail=f"Agent '{name}' not found")
    return {"agent": agent}


@router.delete("/api/agents/{name}")
async def api_delete_agent(name: str):
    if not get_agent(name):
        raise HTTPException(status_code=404, detail=f"Agent '{name}' not found")
    delete_agent(name)
    delete_agent_secrets(name)
    return {"status": "deleted", "name": name}


# --- Activation ---


@router.post("/api/agents/{name}/activate")
async def api_activate_agent(name: str):
    """Load an agent's model configuration into the running pipeline."""
    from server.app import pipeline
    from roohai.pipeline import _register_from_config

    agent = get_agent(name)
    if not agent:
        raise HTTPException(status_code=404, detail=f"Agent '{name}' not found")
    if pipeline is None:
        raise HTTPException(status_code=503, detail="Rooh pipeline not initialized")

    # Deactivate all other active agents first
    all_agents = list_agents()
    for other in all_agents:
        if other.get("status") == "active" and other["name"] != name:
            other["status"] = "inactive"
            save_agent(other)

    # Merge agent secrets into model configs for cloud models
    secrets = get_agent_secrets(name)
    models = agent.get("models", {})
    for model_name, model_cfg in models.items():
        model_secrets = secrets.get(model_name, {})
        if model_secrets:
            model_cfg.update(model_secrets)

    # Register the agent's models into the registry
    agent_as_config = {"models": models}
    _register_from_config(agent_as_config)

    # Validate llm_hook before committing to activation
    # Add the agents directory to sys.path so agent-local hook
    # modules (e.g. hooks.py alongside agent YAMLs) are importable.
    import sys
    from roohai.agents import AGENTS_DIR
    agents_dir_str = str(AGENTS_DIR)
    if agents_dir_str not in sys.path:
        sys.path.insert(0, agents_dir_str)

    hook_path = agent.get("llm_hook")
    hook_fn = None
    stream_hook_fn = None
    if hook_path:
        import importlib
        module_path, _, attr = hook_path.rpartition(".")
        try:
            mod = importlib.import_module(module_path)
            hook_fn = getattr(mod, attr)
        except (ModuleNotFoundError, AttributeError) as exc:
            raise HTTPException(
                status_code=422,
                detail=f"Cannot activate agent '{name}': llm_hook '{hook_path}' could not be resolved — {exc}",
            )
    stream_hook_path = agent.get("llm_stream_hook")
    if stream_hook_path:
        import importlib
        module_path, _, attr = stream_hook_path.rpartition(".")
        try:
            mod = importlib.import_module(module_path)
            stream_hook_fn = getattr(mod, attr)
        except (ModuleNotFoundError, AttributeError) as exc:
            raise HTTPException(
                status_code=422,
                detail=f"Cannot activate agent '{name}': llm_stream_hook '{stream_hook_path}' could not be resolved — {exc}",
            )

    # Swap each model in the pipeline
    agent_pipeline = agent.get("pipeline", {})
    for model_type in ("stt", "tts", "llm", "vad"):
        model_name = agent_pipeline.get(model_type)
        if model_name:
            try:
                await asyncio.to_thread(pipeline.swap_model, model_type, model_name)
            except Exception as exc:
                raise HTTPException(
                    status_code=422,
                    detail=f"Cannot activate agent '{name}': failed to load {model_type} model '{model_name}' — {exc}",
                )

    # Set system prompt and LLM streaming preference on pipeline
    pipeline.set_system_prompt(agent.get("system_prompt"))
    pipeline.llm_streaming = agent.get("llm_streaming", True)

    # Apply validated hooks (or clear if agent has none)
    if hook_fn:
        pipeline.set_llm_hook(hook_fn, stream_hook=stream_hook_fn)
    else:
        pipeline.set_llm_hook(None)

    # Update agent status
    agent["status"] = "active"
    save_agent(agent)

    return {
        "status": "activated",
        "agent": name,
        "transport": agent.get("transport", "websocket"),
        "active_models": {
            "stt": pipeline._stt_name,
            "tts": pipeline._tts_name,
            "llm": pipeline._llm_name,
        }
    }
