import asyncio
from typing import Literal

from fastapi import APIRouter, Header, HTTPException, status
from pydantic import BaseModel

from app.config import settings
from app.services.llm.service_status_manager import ServiceMode, get_status_manager
from common_logging import get_logger

logger = get_logger(__name__)
router = APIRouter()


def _get_script_path() -> str:
    return settings.SWITCH_MODE_SCRIPT


class SwitchModeRequest(BaseModel):
    mode: Literal["inference", "training", "media_processing"]
    training_info: dict | None = None


def _verify_internal_token(token: str) -> None:
    expected = getattr(settings, "INTERNAL_API_TOKEN", None)
    if not expected:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="INTERNAL_API_TOKEN is not configured on this server.",
        )
    if token != expected:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Invalid internal token.")


async def _run_switch_script(mode: str) -> None:
    script_path = _get_script_path()
    try:
        proc = await asyncio.create_subprocess_exec(
            "bash",
            script_path,
            mode,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.STDOUT,
        )
        stdout, _ = await proc.communicate()
        output = stdout.decode(errors="replace") if stdout else ""
        if proc.returncode != 0:
            logger.error(f"switch_mode.sh exited {proc.returncode}: {output}")
        else:
            logger.info(f"switch_mode.sh completed for mode={mode}: {output[:200]}")
    except Exception as e:
        logger.error(f"Failed to run switch_mode.sh: {e}")


@router.post("/switch_mode", summary="Switch LLM service mode (internal)")
async def switch_mode(
    body: SwitchModeRequest, x_internal_token: str = Header(..., alias="X-Internal-Token")
):
    _verify_internal_token(x_internal_token)
    manager = get_status_manager()
    target_mode = ServiceMode(body.mode)
    manager.set_mode(ServiceMode.SWITCHING)
    logger.info(f"Mode switch initiated: target={body.mode}")
    if target_mode == ServiceMode.TRAINING and body.training_info:
        import json

        from app.services.llm.service_status_manager import REDIS_KEY_TRAINING_INFO

        manager._redis.set(REDIS_KEY_TRAINING_INFO, json.dumps(body.training_info))
    asyncio.create_task(_background_switch(manager, target_mode, body.training_info))
    return {
        "status": "switching",
        "target_mode": body.mode,
        "message": f"Mode switch to '{body.mode}' initiated. Service will be in switching state until complete.",
    }


async def _background_switch(
    manager, target_mode: ServiceMode, training_info: dict | None
) -> None:
    try:
        await _run_switch_script(target_mode.value)
        manager.set_mode(target_mode, training_info=training_info)
        logger.info(f"Mode switch complete: now in {target_mode.value} mode")
    except Exception as e:
        logger.error(f"Background switch failed: {e}. Reverting to inference mode.")
        manager.set_mode(ServiceMode.INFERENCE)
        raise
