from __future__ import annotations

from functools import lru_cache
from pathlib import Path

from fastapi import APIRouter, FastAPI, WebSocket
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from loguru import logger

from .config import EngineConfig, load_config, resolve_voice_config_path
from .pipeline import run_product_voice_pipeline

PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
VOICE_DEMO_DIR = PROJECT_ROOT / "static" / "voice-demo"

router = APIRouter(tags=["voice"])


@lru_cache(maxsize=1)
def get_voice_config() -> EngineConfig:
    return load_config()


@lru_cache(maxsize=1)
def get_voice_config_path() -> Path:
    return resolve_voice_config_path()


def _normalize_mount_path(path: str) -> str:
    normalized = path.strip() or "/voice-demo"
    if not normalized.startswith("/"):
        normalized = f"/{normalized}"
    return normalized.rstrip("/") or "/"


@router.get("/voice/health")
async def voice_health() -> dict[str, object]:
    config = get_voice_config()
    mount = (
        _normalize_mount_path(config.server.webpage_mount)
        if config.server.serve_webpage
        else None
    )
    return {
        "status": "healthy",
        "config": str(get_voice_config_path()),
        "protocols": {
            "/ws-product": "va.ws.v1.json_base64",
        },
        "features": {
            "product_text_input": True,
            "product_text_interrupt": True,
        },
        "demo": mount,
        "llm_provider": config.services.llm.provider,
        "stt_provider": config.services.stt.provider,
        "tts_provider": config.services.tts.provider,
    }


@router.websocket("/ws-product")
async def product_websocket_endpoint(websocket: WebSocket) -> None:
    await websocket.accept()
    config = get_voice_config()
    await run_product_voice_pipeline(websocket, config)


def register_voice(app: FastAPI) -> None:
    """Mount voice websocket routes and optional browser demo static files."""
    voice_config_path = get_voice_config_path()
    if not voice_config_path.exists():
        logger.warning(f"Voice config not found at {voice_config_path}; voice demo disabled")
        return

    config = get_voice_config()
    app.include_router(router)
    logger.info(f"Voice config loaded from {voice_config_path}")

    if config.server.cors_origins:
        app.add_middleware(
            CORSMiddleware,
            allow_origins=config.server.cors_origins,
            allow_credentials=True,
            allow_methods=["*"],
            allow_headers=["*"],
        )

    if config.server.serve_webpage and VOICE_DEMO_DIR.is_dir():
        mount = _normalize_mount_path(config.server.webpage_mount)
        app.mount(
            mount,
            StaticFiles(directory=str(VOICE_DEMO_DIR), html=True),
            name="voice-demo",
        )
        logger.info(f"Voice demo mounted at {mount}")
    else:
        logger.info("Voice demo static page disabled or missing")

    logger.info("Voice websocket registered at /ws-product")
