"""Live Gemini Subprocess control endpoints."""

from __future__ import annotations

import asyncio

from fastapi import APIRouter, HTTPException, Query

from Project.Sanad.config import BASE_DIR
from Project.Sanad.vision import recognition_state

router = APIRouter()

_STATE_PATH = BASE_DIR / "data" / ".recognition_state.json"


def _sub_or_503():
    from Project.Sanad.main import live_sub
    if live_sub is None:
        raise HTTPException(503, "Live subprocess not available")
    return live_sub


@router.get("/status")
async def subprocess_status():
    from Project.Sanad.main import live_sub
    # record_enabled is a live flag (recognition_state) the panel toggle drives;
    # surface it so the UI shows the current state even before a session starts.
    rec = bool(recognition_state.read(_STATE_PATH).record_enabled)
    if live_sub is None:
        return {"available": False, "state": "unavailable", "record_enabled": rec}
    return {**live_sub.status(), "record_enabled": rec}


@router.post("/record")
async def set_record(on: bool = Query(...)):
    """Toggle auto-recording of conversation turns to data/recordings/. Takes
    effect live (the voice child syncs its recorder) — no session restart."""
    st = await asyncio.to_thread(
        recognition_state.mutate, _STATE_PATH, record_enabled=bool(on))
    return {"ok": True, "record_enabled": st.record_enabled}


_VOICE_OPTS_PATH = BASE_DIR / "data" / ".voice_options.json"


def _read_voice_opts() -> dict:
    import json
    try:
        with open(_VOICE_OPTS_PATH, encoding="utf-8") as f:
            d = json.load(f)
        return d if isinstance(d, dict) else {}
    except Exception:
        return {}


@router.get("/interrupt-option")
async def get_interrupt_option():
    """Voice interrupt (barge-in) — GLOBAL, all speakers. OFF: Sanad always
    finishes his sentence on every profile (chest/Anker/JBL/Beats Pill — mic
    fully gated while he speaks). ON: loud sustained speech cuts him.
    Resolution: dashboard toggle (data/.voice_options.json) >
    SANAD_EXTERNAL_BARGE_IN env > voice_config.json barge_in.external_barge_in
    > off."""
    import os
    opts = _read_voice_opts()
    if "external_barge_in" in opts:
        return {"enabled": bool(opts["external_barge_in"]), "source": "dashboard"}
    env = os.environ.get("SANAD_EXTERNAL_BARGE_IN", "").strip().lower()
    if env in ("1", "true", "yes"):
        return {"enabled": True, "source": "env"}
    try:
        from Project.Sanad.core.config_loader import section
        if bool((section("voice", "barge_in") or {}).get("external_barge_in", False)):
            return {"enabled": True, "source": "config"}
    except Exception:
        pass
    return {"enabled": False, "source": "default"}


@router.post("/interrupt-option")
async def set_interrupt_option(on: bool = Query(...)):
    """Persist the interrupt option (survives rebuilds — data/ is mounted) and
    restart the live session so the voice child picks it up."""
    import json
    import tempfile
    import os as _os
    opts = _read_voice_opts()
    opts["external_barge_in"] = bool(on)
    _VOICE_OPTS_PATH.parent.mkdir(parents=True, exist_ok=True)
    fd, tmp = tempfile.mkstemp(dir=str(_VOICE_OPTS_PATH.parent),
                               prefix=".voice_options.", suffix=".tmp")
    with _os.fdopen(fd, "w", encoding="utf-8") as f:
        json.dump(opts, f, indent=2)
    _os.replace(tmp, _VOICE_OPTS_PATH)

    restarted = False
    from Project.Sanad.main import live_sub
    if live_sub is not None:
        try:
            if (live_sub.status() or {}).get("running"):
                await asyncio.to_thread(live_sub.stop)
                await asyncio.to_thread(live_sub.start)
                restarted = True
        except Exception:
            pass
    return {"ok": True, "enabled": bool(on), "restarted": restarted}


@router.get("/direct-answer-option")
async def get_direct_answer_option():
    """'Direct answer' = Gemini replies as soon as the speaker pauses (Live-API
    end-of-speech sensitivity HIGH). Resolution: dashboard > env > config."""
    import os
    opts = _read_voice_opts()
    if "direct_answer" in opts:
        return {"enabled": bool(opts["direct_answer"]), "source": "dashboard"}
    if os.environ.get("SANAD_DIRECT_ANSWER", "").strip().lower() in ("1", "true", "yes"):
        return {"enabled": True, "source": "env"}
    try:
        from Project.Sanad.core.config_loader import section
        if bool((section("voice", "vad") or {}).get("direct_answer", False)):
            return {"enabled": True, "source": "config"}
    except Exception:
        pass
    return {"enabled": False, "source": "default"}


@router.post("/direct-answer-option")
async def set_direct_answer_option(on: bool = Query(...)):
    """Persist the direct-answer option and restart the live session."""
    import json
    import tempfile
    import os as _os
    opts = _read_voice_opts()
    opts["direct_answer"] = bool(on)
    _VOICE_OPTS_PATH.parent.mkdir(parents=True, exist_ok=True)
    fd, tmp = tempfile.mkstemp(dir=str(_VOICE_OPTS_PATH.parent),
                               prefix=".voice_options.", suffix=".tmp")
    with _os.fdopen(fd, "w", encoding="utf-8") as f:
        json.dump(opts, f, indent=2)
    _os.replace(tmp, _VOICE_OPTS_PATH)
    restarted = False
    from Project.Sanad.main import live_sub
    if live_sub is not None:
        try:
            if (live_sub.status() or {}).get("running"):
                await asyncio.to_thread(live_sub.stop)
                await asyncio.to_thread(live_sub.start)
                restarted = True
        except Exception:
            pass
    return {"ok": True, "enabled": bool(on), "restarted": restarted}


@router.get("/pure-voice-option")
async def get_pure_voice_option():
    """PURE VOICE = the live session built exactly like standalone Sanadv1:
    no tools, no state injections, persona only, no lip-sync markers — the
    fastest conversation pipe. Resolution: dashboard > env > config."""
    import os
    opts = _read_voice_opts()
    if "pure_voice" in opts:
        return {"enabled": bool(opts["pure_voice"]), "source": "dashboard"}
    if os.environ.get("SANAD_PURE_VOICE", "").strip().lower() in ("1", "true", "yes"):
        return {"enabled": True, "source": "env"}
    try:
        from Project.Sanad.core.config_loader import section
        if bool((section("voice", "sanad_voice") or {}).get("pure_voice", False)):
            return {"enabled": True, "source": "config"}
    except Exception:
        pass
    return {"enabled": False, "source": "default"}


@router.post("/pure-voice-option")
async def set_pure_voice_option(on: bool = Query(...)):
    """Persist the pure-voice option and restart the live session."""
    import json
    import tempfile
    import os as _os
    opts = _read_voice_opts()
    opts["pure_voice"] = bool(on)
    _VOICE_OPTS_PATH.parent.mkdir(parents=True, exist_ok=True)
    fd, tmp = tempfile.mkstemp(dir=str(_VOICE_OPTS_PATH.parent),
                               prefix=".voice_options.", suffix=".tmp")
    with _os.fdopen(fd, "w", encoding="utf-8") as f:
        json.dump(opts, f, indent=2)
    _os.replace(tmp, _VOICE_OPTS_PATH)
    restarted = False
    from Project.Sanad.main import live_sub
    if live_sub is not None:
        try:
            if (live_sub.status() or {}).get("running"):
                await asyncio.to_thread(live_sub.stop)
                await asyncio.to_thread(live_sub.start)
                restarted = True
        except Exception:
            pass
    return {"ok": True, "enabled": bool(on), "restarted": restarted}


@router.get("/internet-search-option")
async def get_internet_search_option():
    """INTERNET SEARCH = the live session gets the search_internet tool so Gemini
    can look up current facts (prices, latest phones, live offers, news) via
    Google Search grounding, announcing the search first. Resolution:
    dashboard > env > config."""
    import os
    opts = _read_voice_opts()
    if "internet_search" in opts:
        return {"enabled": bool(opts["internet_search"]), "source": "dashboard"}
    if os.environ.get("SANAD_INTERNET_SEARCH", "").strip().lower() in ("1", "true", "yes"):
        return {"enabled": True, "source": "env"}
    try:
        from Project.Sanad.core.config_loader import section
        if bool((section("voice", "sanad_voice") or {}).get("internet_search", False)):
            return {"enabled": True, "source": "config"}
    except Exception:
        pass
    return {"enabled": False, "source": "default"}


@router.post("/internet-search-option")
async def set_internet_search_option(on: bool = Query(...)):
    """Persist the internet-search option and restart the live session so the
    tool set (and persona addendum) is rebaked."""
    import json
    import tempfile
    import os as _os
    opts = _read_voice_opts()
    opts["internet_search"] = bool(on)
    _VOICE_OPTS_PATH.parent.mkdir(parents=True, exist_ok=True)
    fd, tmp = tempfile.mkstemp(dir=str(_VOICE_OPTS_PATH.parent),
                               prefix=".voice_options.", suffix=".tmp")
    with _os.fdopen(fd, "w", encoding="utf-8") as f:
        json.dump(opts, f, indent=2)
    _os.replace(tmp, _VOICE_OPTS_PATH)
    restarted = False
    from Project.Sanad.main import live_sub
    if live_sub is not None:
        try:
            if (live_sub.status() or {}).get("running"):
                await asyncio.to_thread(live_sub.stop)
                await asyncio.to_thread(live_sub.start)
                restarted = True
        except Exception:
            pass
    return {"ok": True, "enabled": bool(on), "restarted": restarted}


@router.post("/answer-now")
async def answer_now():
    """Force Gemini to reply immediately instead of waiting out the pause
    detection (no-op while it is already speaking)."""
    sub = _sub_or_503()
    if not (sub.status() or {}).get("running"):
        raise HTTPException(409, "Live session not running")
    if not hasattr(sub, "send_answer_now"):
        raise HTTPException(501, "engine build lacks send_answer_now")
    await asyncio.to_thread(sub.send_answer_now)
    return {"ok": True}


@router.post("/interrupt")
async def interrupt_speech():
    """Instantly stop the AI mid-sentence and go back to listening (works
    regardless of the barge-in option; no-op if it isn't speaking)."""
    sub = _sub_or_503()
    if not (sub.status() or {}).get("running"):
        raise HTTPException(409, "Live session not running")
    if not hasattr(sub, "send_interrupt"):
        raise HTTPException(501, "engine build lacks send_interrupt")
    await asyncio.to_thread(sub.send_interrupt)
    return {"ok": True}


@router.post("/start")
async def start_subprocess():
    live_sub = _sub_or_503()
    try:
        return await asyncio.to_thread(live_sub.start)
    except RuntimeError as exc:
        raise HTTPException(404, str(exc))


@router.post("/stop")
async def stop_subprocess():
    return await asyncio.to_thread(_sub_or_503().stop)
