#!/usr/bin/env python3
"""Инференс joint-модели планшета: CLI и HTTP-служба.

Разовый разбор:
    python predict.py "поставь таймер на 15 минут"
    python predict.py "включи Ваню Дмитриенко"

HTTP-служба (для app/api/voice/chat/route.ts как локальный «мозг»):
    python predict.py --serve --port 8091
    # POST /predict {"text": "..."} → {intent, slots, score, tool}
    # score < THRESHOLD → intent принудительно none (порог на стороне службы,
    # но потребитель всё равно решает сам падать ли на облачный LLM).

Порог THRESHOLD=0.7 по умолчанию (переопределяется env).
"""
import argparse
import json
import os
import sys

import joint_model_def as jm
import tablet_map

HERE = os.path.dirname(os.path.abspath(__file__))
MODEL_DIR = os.path.join(HERE, "joint_model")
THRESHOLD = float(os.environ.get("THRESHOLD", "0.7"))

_model = _tok = _cfg = None


def _ensure_loaded():
    global _model, _tok, _cfg
    if _model is None:
        _model, _tok, _cfg = jm.load(MODEL_DIR)
        jm.predict(_model, _tok, _cfg, "прогрев")   # первый форвард медленнее


def analyze(text):
    _ensure_loaded()
    intent, slots, score = jm.predict(_model, _tok, _cfg, text)
    if score < THRESHOLD:
        intent = "none"
    tool = tablet_map.to_tool_call(intent, slots) if intent != "none" else None
    return {"intent": intent, "slots": slots, "score": round(score, 3), "tool": tool}


def serve(port):
    from http.server import BaseHTTPRequestHandler, HTTPServer

    class Handler(BaseHTTPRequestHandler):
        def _send(self, code, obj):
            body = json.dumps(obj, ensure_ascii=False).encode("utf-8")
            self.send_response(code)
            self.send_header("Content-Type", "application/json; charset=utf-8")
            self.send_header("Content-Length", str(len(body)))
            self.end_headers()
            self.wfile.write(body)

        def do_GET(self):
            if self.path == "/health":
                self._send(200, {"ok": True})
            else:
                self._send(404, {"error": "not found"})

        def do_POST(self):
            if self.path != "/predict":
                return self._send(404, {"error": "not found"})
            n = int(self.headers.get("Content-Length", 0))
            try:
                data = json.loads(self.rfile.read(n) or b"{}")
                text = (data.get("text") or "").strip()
            except Exception:
                return self._send(400, {"error": "bad json"})
            if not text:
                return self._send(400, {"error": "empty text"})
            self._send(200, analyze(text))

        def log_message(self, *a):
            pass   # тихо

    _ensure_loaded()
    print(f"tablet-agent слушает http://127.0.0.1:{port}  (порог {THRESHOLD})")
    HTTPServer(("127.0.0.1", port), Handler).serve_forever()


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("text", nargs="*", help="запрос для разбора")
    ap.add_argument("--serve", action="store_true", help="поднять HTTP-службу")
    ap.add_argument("--port", type=int, default=8091)
    args = ap.parse_args()

    if args.serve:
        serve(args.port)
        return

    if not args.text:
        print("Использование: python predict.py \"текст запроса\"")
        sys.exit(1)
    print(json.dumps(analyze(" ".join(args.text)), ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()
