"""
routes_record.py — Endpoint rekaman mic (upload blob + WebSocket live).

Perubahan dari versi sebelumnya:
- POST /api/record/upload sekarang wajib login dan mencatat user_id pada task.
- WebSocket /api/record/live tidak mengubah auth (koneksi WS lebih kompleks
  untuk JWT; gunakan query-param token jika diperlukan di masa depan).
"""

import os
import uuid
import json
import tempfile

from fastapi import (
    APIRouter, WebSocket, WebSocketDisconnect,
    UploadFile, File, Form, Depends, BackgroundTasks, HTTPException,
)
from sqlalchemy.orm import Session

from app.core.database import get_db
from app.models.user import User
from app.services.auth_service import get_current_user
from app.services.task_service import create_task
from app.services.whisper_local import transcribe_local
from app.services.whisper_api import transcribe_api
from app.utils.whisper_worker import run_in_threadpool
from app.services.transcription_service import process_task
from app.core.config import (
    UPLOAD_DIR, ENGINE_LOCAL, ENGINE_API,
    ALLOWED_EXTENSIONS, MAX_FILE_SIZE_BYTES,
)

router = APIRouter()


# ================================================================
# Helper
# ================================================================
async def _run_transcription_async(task_id: int) -> None:
    await run_in_threadpool(process_task, task_id)


# ================================================================
# POST /api/record/upload
# Upload hasil rekaman mic → proses seperti file biasa
# ================================================================
@router.post("/record/upload")
async def upload_recording(
    background_tasks: BackgroundTasks,
    file:          UploadFile = File(...),
    engine:        str        = Form(default=ENGINE_LOCAL),
    model_type:    str        = Form(default="base"),
    is_court_mode: bool       = Form(default=False),
    db:            Session    = Depends(get_db),
    current_user:  User       = Depends(get_current_user),   # ← wajib login
):
    if engine not in (ENGINE_LOCAL, ENGINE_API):
        raise HTTPException(
            status_code=400,
            detail=f"Engine tidak valid. Pilihan: {ENGINE_LOCAL}, {ENGINE_API}",
        )

    # Tentukan ekstensi
    original_name = file.filename or "rekaman.webm"
    ext = os.path.splitext(original_name)[-1].lower() or ".webm"
    if ext not in ALLOWED_EXTENSIONS:
        ext = ".webm"

    # Baca dan validasi ukuran sebelum simpan ke disk
    contents = await file.read()
    if len(contents) > MAX_FILE_SIZE_BYTES:
        raise HTTPException(
            status_code=413,
            detail=(
                f"Ukuran file melebihi batas maksimum "
                f"{MAX_FILE_SIZE_BYTES // (1024 * 1024)} MB."
            ),
        )
    if not contents:
        raise HTTPException(status_code=400, detail="File rekaman kosong.")

    # Simpan ke disk
    unique_name = f"rec_{uuid.uuid4().hex}{ext}"
    file_path   = str(UPLOAD_DIR / unique_name)
    with open(file_path, "wb") as f:
        f.write(contents)

    # Buat task dengan user_id
    task = create_task(
        db=db,
        model_type=model_type,
        file_path=file_path,
        engine=engine,
        is_court_mode=is_court_mode,
        user_id=current_user.id,        # ← catat pemilik
    )

    background_tasks.add_task(_run_transcription_async, task.id)

    return {
        "success":   True,
        "task_id":   task.id,
        "task_uuid": task.task_uuid,
        "message":   "Rekaman berhasil dikirim. Transkripsi sedang berjalan.",
    }


# ================================================================
# WebSocket /api/record/live
# Live transkripsi: kirim chunk audio tiap N detik → terima teks
# Catatan: result live TIDAK dienkripsi karena bersifat sementara
# (tidak disimpan ke DB).
# ================================================================
@router.websocket("/record/live")
async def live_transcription(websocket: WebSocket):
    await websocket.accept()
    await websocket.send_json({
        "type":    "connected",
        "message": "WebSocket terhubung. Siap menerima audio.",
    })

    config = {"engine": ENGINE_LOCAL, "model_type": "base"}

    try:
        while True:
            message = await websocket.receive()

            # ── Config message (JSON teks) ──────────────────────────
            if "text" in message:
                try:
                    data = json.loads(message["text"])

                    if data.get("type") == "config":
                        engine_val = data.get("engine", ENGINE_LOCAL)
                        model_val  = data.get("model_type", "base")

                        if engine_val not in (ENGINE_LOCAL, ENGINE_API):
                            await websocket.send_json({
                                "type":    "error",
                                "message": f"Engine tidak valid: {engine_val}",
                            })
                            continue

                        config["engine"]     = engine_val
                        config["model_type"] = model_val
                        await websocket.send_json({
                            "type":    "config_ok",
                            "message": (
                                f"Config diterima: engine={config['engine']}, "
                                f"model={config['model_type']}"
                            ),
                        })

                    elif data.get("type") == "ping":
                        await websocket.send_json({"type": "pong"})

                except (json.JSONDecodeError, TypeError):
                    pass
                continue

            # ── Audio chunk (bytes) ─────────────────────────────────
            audio_bytes: bytes = message.get("bytes")
            if not audio_bytes:
                continue

            if len(audio_bytes) > MAX_FILE_SIZE_BYTES:
                await websocket.send_json({
                    "type":    "error",
                    "message": "Chunk audio terlalu besar.",
                })
                continue

            tmp_path = None
            try:
                with tempfile.NamedTemporaryFile(
                    delete=False,
                    suffix=".webm",
                    dir=str(UPLOAD_DIR),
                    prefix="live_",
                ) as tmp:
                    tmp.write(audio_bytes)
                    tmp_path = tmp.name

                await websocket.send_json({
                    "type": "processing", "message": "Memproses chunk audio..."
                })

                if config["engine"] == ENGINE_LOCAL:
                    output = await run_in_threadpool(
                        transcribe_local, tmp_path, config["model_type"]
                    )
                else:
                    output = await run_in_threadpool(transcribe_api, tmp_path)

                text = output.get("text", "").strip()
                if text:
                    await websocket.send_json({
                        "type":            "transcript",
                        "text":            text,
                        "processing_time": output.get("processing_time"),
                    })
                else:
                    await websocket.send_json({
                        "type":    "empty",
                        "message": "Tidak ada suara yang terdeteksi pada chunk ini.",
                    })

            except Exception as e:
                await websocket.send_json({"type": "error", "message": str(e)})

            finally:
                if tmp_path:
                    try:
                        os.remove(tmp_path)
                    except OSError:
                        pass

    except WebSocketDisconnect:
        pass
    except Exception as e:
        try:
            await websocket.send_json({"type": "error", "message": str(e)})
        except Exception:
            pass