"""Typed Replay dashboard endpoints.

Full CRUD over the records index:
  POST /say                     generate + play + optionally record
  POST /replay-last             re-play cached audio
  POST /save-last               persist cached generation
  GET  /records                 list
  GET  /records/{name}          get one
  POST /records/{name}/play     play saved WAV (speaker or raw)
  POST /records/{name}/rename   rename
  DELETE /records/{name}        delete
  GET  /status                  engine + session state
"""

from __future__ import annotations

import asyncio
from typing import Literal

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel

from Project.Sanad.core.config_loader import section as _cfg_section
router = APIRouter()

# MAX_TEXT_LEN — SINGLE SOURCE in dashboard.api_input
MAX_TEXT_LEN = _cfg_section("dashboard", "api_input").get("max_text_len", 2000)


class SayPayload(BaseModel):
    text: str
    record: bool = False
    record_name: str = ""


class SaveLastPayload(BaseModel):
    record_name: str = ""


class RenamePayload(BaseModel):
    new_name: str


class PlayRecordPayload(BaseModel):
    file_kind: Literal["speaker", "raw"] = "speaker"


def _engine():
    from Project.Sanad.main import typed_replay
    if typed_replay is None:
        raise HTTPException(503, "TypedReplayEngine not initialized.")
    return typed_replay


# ───────────────────── generate / replay ─────────────────────

@router.post("/say")
async def say(payload: SayPayload):
    if not payload.text or not payload.text.strip():
        raise HTTPException(400, "text cannot be empty")
    if len(payload.text) > MAX_TEXT_LEN:
        raise HTTPException(413, f"text too long (max {MAX_TEXT_LEN})")
    eng = _engine()
    try:
        return await eng.say(payload.text, record=payload.record,
                              record_name=payload.record_name)
    except ValueError as exc:
        raise HTTPException(400, str(exc))
    except RuntimeError as exc:
        raise HTTPException(503, str(exc))


@router.post("/replay-last")
async def replay_last():
    eng = _engine()
    try:
        return await asyncio.to_thread(eng.replay_last)
    except RuntimeError as exc:
        raise HTTPException(400, str(exc))


@router.post("/save-last")
async def save_last(payload: SaveLastPayload):
    eng = _engine()
    try:
        return {"ok": True, "record": eng.save_last(payload.record_name)}
    except RuntimeError as exc:
        raise HTTPException(400, str(exc))


# ───────────────────── record CRUD ───────────────────────────

@router.get("/records")
async def list_records():
    return _engine().list_records()


@router.get("/records/{name}")
async def get_record(name: str):
    try:
        return _engine().find_record(name)
    except KeyError:
        raise HTTPException(404, f"record not found: {name}")


@router.post("/records/{name}/play")
async def play_record(name: str, payload: PlayRecordPayload):
    eng = _engine()
    try:
        return await asyncio.to_thread(eng.play_record, name, payload.file_kind)
    except KeyError:
        raise HTTPException(404, f"record not found: {name}")
    except FileNotFoundError as exc:
        raise HTTPException(410, f"file missing on disk: {exc}")
    except RuntimeError as exc:
        raise HTTPException(503, str(exc))


@router.post("/records/{name}/rename")
async def rename_record(name: str, payload: RenamePayload):
    eng = _engine()
    try:
        return {"ok": True, "record": eng.rename_record(name, payload.new_name)}
    except KeyError:
        raise HTTPException(404, f"record not found: {name}")
    except ValueError as exc:
        raise HTTPException(400, str(exc))


@router.delete("/records/{name}")
async def delete_record(name: str):
    eng = _engine()
    try:
        return {"ok": True, **eng.delete_record(name)}
    except KeyError:
        raise HTTPException(404, f"record not found: {name}")


# ───────────────────── status ────────────────────────────────

@router.get("/status")
async def status():
    from Project.Sanad.main import typed_replay
    if typed_replay is None:
        return {"available": False}
    return {"available": True, **typed_replay.status()}
