"""Plappi-MVP API.

Das eigentliche Produkt-„Gehirn". Clients (heute Handy-PWA, morgen Raspberry Pi)
sprechen NUR mit diesem Backend über /api/turn — Mikro rein, ASR -> Dialog -> TTS,
Audio raus. Der Client bleibt dumm; alle Intelligenz lebt hier.
"""
from __future__ import annotations

import time
import uuid
from pathlib import Path

from fastapi import FastAPI, File, Form, Request, UploadFile
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from fastapi.staticfiles import StaticFiles

from . import animals, asr, config, dialog, profile, sessions, stories, store, tts, voices

app = FastAPI(title="Plappi MVP", version="0.1.0")
app.add_middleware(
    CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"],
)


@app.middleware("http")
async def _no_cache_static(request, call_next):
    """HTML/JS/Manifest nie cachen → Frontend-Updates kommen sofort an (kein „App updaten")."""
    resp = await call_next(request)
    p = request.url.path
    if p == "/" or p.endswith((".html", ".js", ".webmanifest")):
        resp.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"
        resp.headers["Pragma"] = "no-cache"
    return resp


@app.get("/api/health")
def health():
    return {
        "ok": True,
        "child_lang": config.lang_name(config.CHILD_LANG),
        "target_lang": config.lang_name(config.TARGET_LANG),
        "voice": config.PLAPPI_VOICE,
        "model": config.DIALOG_MODEL,
    }


@app.get("/api/clientconfig")
def clientconfig():
    cfg = config.client_config()
    cfg["agent_id"] = config.ELEVENLABS_AGENT_ID
    return cfg


@app.get("/api/agent")
def agent():
    return {"agent_id": config.ELEVENLABS_AGENT_ID,
            "child_lang": config.lang_name(config.CHILD_LANG),
            "target_lang": config.lang_name(config.TARGET_LANG),
            "profile": profile.get_profile()}


@app.get("/api/profile")
def get_profile():
    return profile.get_profile()


@app.post("/api/profile")
async def set_profile(request: Request):
    data = await request.json()
    return profile.save_profile(data)


@app.get("/api/voices")
def get_voices():
    return voices.list_voices()


@app.post("/api/voice")
async def set_voice(request: Request):
    data = await request.json()
    return voices.set_active(data.get("voice_id", ""))


@app.get("/api/curriculum")
def curriculum():
    return {"themes": {t: [{"sr": sr, "de": de} for sr, de in words]
                       for t, words in profile.CURRICULUM.items()},
            "sensitive_presets": profile.SENSITIVE_PRESETS}


@app.get("/api/stories")
def get_stories():
    return {"stories": stories.list_stories()}


@app.get("/api/animals")
def get_animals():
    return {"animals": animals.list_animals()}


@app.post("/api/sync")
def sync():
    try:
        return store.sync()
    except Exception as e:  # noqa: BLE001
        return JSONResponse({"ok": False, "error": str(e)}, status_code=200)


@app.get("/api/dashboard")
def dashboard():
    # frisch ziehen (best effort), dann gespeicherte Daten liefern
    try:
        store.sync()
    except Exception as e:  # noqa: BLE001
        print(f"[dashboard] sync failed: {e}", flush=True)
    return store.dashboard_data()


@app.post("/api/reset")
def reset(session_id: str = Form(...)):
    sessions.reset(session_id)
    return {"ok": True}


def _audio_url(name: str) -> str:
    return f"/audio/{name}"


@app.post("/api/turn")
async def turn(session_id: str = Form(...), audio: UploadFile = File(...)):
    """Ein kompletter Gesprächs-Turn: Sprach-Clip -> Plappis gesprochene Antwort."""
    t0 = time.time()
    suffix = Path(audio.filename or "clip.webm").suffix or ".webm"
    raw = config.UPLOAD_DIR / f"{uuid.uuid4().hex}{suffix}"
    raw.write_bytes(await audio.read())

    child_text, child_lang = asr.transcribe(raw)
    reply = dialog.respond(session_id, child_text)
    audio_name = await tts.synthesize(reply, voice="d3l4f3HgkE3P6Fo91lYA")  # Ida (von Nemanja freigegeben)

    return JSONResponse({
        "session_id": session_id,
        "child_text": child_text,
        "child_lang": child_lang,
        "plappi_text": reply,
        "audio_url": _audio_url(audio_name),
        "ms": int((time.time() - t0) * 1000),
    })


@app.post("/api/say")
async def say(session_id: str = Form(...), text: str = Form(...)):
    """Debug/Test-Pfad ohne Mikro: Text rein -> Dialog + TTS raus."""
    reply = dialog.respond(session_id, text)
    audio_name = await tts.synthesize(reply, voice="d3l4f3HgkE3P6Fo91lYA")  # Ida (von Nemanja freigegeben)
    return JSONResponse({
        "session_id": session_id,
        "child_text": text,
        "plappi_text": reply,
        "audio_url": _audio_url(audio_name),
    })


# ── Statische Auslieferung ───────────────────────────────────────────────────
app.mount("/audio", StaticFiles(directory=str(config.AUDIO_DIR)), name="audio")
app.mount("/", StaticFiles(directory=str(config.WEB_DIR), html=True), name="web")
