"""LM Studio preference HTTP routes extracted from [mugi_backend._build_app](mugi_backend.py)."""
from __future__ import annotations

import asyncio
import os
from collections.abc import Callable
from typing import Any

from fastapi import Query as FQuery, Request as FRequest
from fastapi.responses import JSONResponse


def register_llmster_preferences_routes(
    fastapi_app: Any,
    *,
    load_app_prefs: Callable[[], dict[str, Any]],
    save_app_prefs: Callable[[dict[str, Any]], None],
) -> None:
    """Register /preferences/llmster/* routes."""

    @fastapi_app.get("/preferences/llmster/status")
    async def llmster_status():
        error = ""
        try:
            from app_llmster import find_llmster_path, llmster_server_running
            installed = find_llmster_path() is not None
            running = llmster_server_running() if installed else False
        except Exception as exc:
            installed = False
            running = False
            error = str(exc)
        return JSONResponse(content={"installed": installed, "running": running, "error": error})

    @fastapi_app.get("/preferences/llmster/models")
    async def llmster_models():
        error = ""
        try:
            from app_llmster import llmster_list_models
            installed = llmster_list_models() or []
        except Exception as exc:
            installed = []
            error = str(exc)
        prefs = load_app_prefs()
        custom = prefs.get("custom_model_paths") or []
        if isinstance(custom, list):
            for c in custom:
                if isinstance(c, dict):
                    path = (c.get("path") or "").strip()
                    if path and os.path.isabs(path) and (os.path.isfile(path) or os.path.isdir(path)):
                        name = (c.get("display_name") or "").strip() or os.path.basename(path.rstrip(os.sep))
                        installed.append({"key": path, "display_name": name})
        return JSONResponse(content={"installed": installed, "error": error})

    @fastapi_app.post("/preferences/llmster/add-custom-model")
    async def llmster_add_custom_model(request: FRequest):
        try:
            body = await request.json()
        except Exception:
            body = {}
        path = (body.get("path") or "").strip()
        if not path:
            return JSONResponse(content={"ok": False, "message": "path required"}, status_code=400)
        path = os.path.abspath(path)
        if not (os.path.isfile(path) or os.path.isdir(path)):
            return JSONResponse(content={"ok": False, "message": "path does not exist"}, status_code=400)
        display_name = (body.get("display_name") or "").strip() or os.path.basename(path.rstrip(os.sep))
        prefs = load_app_prefs()
        custom = prefs.get("custom_model_paths") or []
        if not isinstance(custom, list):
            custom = []
        for c in custom:
            if isinstance(c, dict) and (c.get("path") or "").strip() == path:
                return JSONResponse(content={"ok": True, "message": "Already added"})
        custom.append({"path": path, "display_name": display_name})
        prefs["custom_model_paths"] = custom
        save_app_prefs(prefs)
        return JSONResponse(content={"ok": True, "message": "Added"})

    @fastapi_app.get("/preferences/llmster/recommended")
    async def llmster_recommended(refresh: bool = FQuery(False)):
        error = ""
        try:
            from app_llmster import get_llmster_recommended_models, clear_lmstudio_catalog_cache
            if refresh:
                clear_lmstudio_catalog_cache()
            recommended, _ = get_llmster_recommended_models()
        except Exception as exc:
            recommended = []
            error = str(exc)
        return JSONResponse(content={"recommended": recommended, "error": error})

    @fastapi_app.post("/preferences/llmster/download")
    async def llmster_download_route(request: FRequest):
        try:
            body = await request.json()
        except Exception:
            body = {}
        model_id = (body.get("model_id") or "").strip()
        if not model_id:
            return JSONResponse(content={"ok": False, "message": "model_id required"}, status_code=400)
        try:
            from app_llmster import llmster_start_download
        except Exception:
            return JSONResponse(content={"ok": False, "message": "llmster not available"}, status_code=500)
        loop = asyncio.get_event_loop()
        try:
            result = await loop.run_in_executor(None, lambda: llmster_start_download(model_id))
            return JSONResponse(content=result)
        except Exception as e:
            return JSONResponse(content={"ok": False, "message": str(e)})

    @fastapi_app.get("/preferences/llmster/download/status/{job_id}")
    async def llmster_download_status_route(job_id: str):
        from utils.llm_token_normalize import normalize_hex_id_token

        job_id = normalize_hex_id_token((job_id or "").strip(), allowed_lengths=(12,))
        try:
            from app_llmster import llmster_download_status
        except Exception:
            return JSONResponse(content={"status": "error", "message": "llmster not available"})
        loop = asyncio.get_event_loop()
        result = await loop.run_in_executor(None, lambda: llmster_download_status(job_id))
        return JSONResponse(content=result)

    @fastapi_app.post("/preferences/llmster/load_model")
    async def llmster_load_model_route(request: FRequest):
        try:
            body = await request.json()
        except Exception:
            body = {}
        model_id = (body.get("model_id") or "").strip()
        if not model_id:
            return JSONResponse(content={"ok": False, "message": "model_id required"}, status_code=400)
        context_length = body.get("context_length")
        try:
            from app_llmster import llmster_load_model
        except Exception:
            return JSONResponse(content={"ok": False, "message": "llmster not available"}, status_code=500)
        loop = asyncio.get_event_loop()
        try:
            result = await loop.run_in_executor(None, lambda: llmster_load_model(model_id, context_length))
            return JSONResponse(content=result)
        except Exception as e:
            return JSONResponse(content={"ok": False, "message": str(e)})

    @fastapi_app.post("/preferences/llmster/install")
    async def llmster_install_route():
        try:
            from app_llmster import _install_llmster
        except Exception:
            return JSONResponse(content={"ok": False, "message": "llmster not available"}, status_code=500)
        loop = asyncio.get_event_loop()
        try:
            ok, msg = await loop.run_in_executor(None, _install_llmster)
            return JSONResponse(content={"ok": ok, "message": msg or ""})
        except Exception as e:
            return JSONResponse(content={"ok": False, "message": str(e)})

    @fastapi_app.post("/preferences/llmster/delete-and-reset")
    async def llmster_delete_and_reset_route():
        try:
            from app_llmster import delete_llmster_and_reset
        except Exception:
            return JSONResponse(content={"ok": False, "message": "llmster not available"}, status_code=500)
        loop = asyncio.get_event_loop()
        try:
            ok, msg = await loop.run_in_executor(None, delete_llmster_and_reset)
            return JSONResponse(content={"ok": ok, "message": msg or ""})
        except Exception as e:
            return JSONResponse(content={"ok": False, "message": str(e)})

    @fastapi_app.post("/preferences/llmster/{action}")
    async def llmster_action(action: str):
        try:
            from app_llmster import start_llmster_server, stop_llmster_server
            loop = asyncio.get_event_loop()
            if action == "start":
                result = await loop.run_in_executor(None, start_llmster_server)
                return JSONResponse(content=result)
            if action == "stop":
                result = await loop.run_in_executor(None, stop_llmster_server)
                return JSONResponse(content=result)
            return JSONResponse(content={"error": "unknown action"}, status_code=400)
        except Exception as exc:
            return JSONResponse(content={"ok": False, "message": str(exc)})
