"""
routes_berita_acara.py — Endpoint untuk fitur Berita Acara Sidang.

Endpoints:
  POST   /api/berita-acara                    — Buat BA baru dari task
  GET    /api/berita-acara/{ba_id}            — Ambil detail BA (Q&A terdekripsi)
  PATCH  /api/berita-acara/{ba_id}            — Simpan edit Q&A dari frontend
  DELETE /api/berita-acara/{ba_id}            — Hapus BA
  GET    /api/berita-acara/by-task/{task_id}  — Daftar BA milik task

Admin-only:
  GET    /api/admin/ba-prompt                 — Ambil prompt aktif
  POST   /api/admin/ba-prompt                 — Simpan/update prompt
"""

import logging
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, BackgroundTasks
from pydantic import BaseModel
from sqlalchemy.orm import Session

from app.core.database import get_db
from app.models.berita_acara import BeritaAcara, BeritaAcaraPrompt
from app.models.transkripsi import TranskripsiTask
from app.models.user import User
from app.services.auth_service import get_current_user, get_current_admin
from app.services.berita_acara_service import (
    get_active_prompt,
    upsert_prompt,
    process_berita_acara,
    get_ba_qa_decrypted,
    save_qa_edits,
    DEFAULT_PROMPT,
)
from app.utils.whisper_worker import run_in_threadpool

# --- Billing imports ---
from app.utils.billing import (
    get_ba_rate,
    deduct_balance,
    refund_balance,
)

router = APIRouter()
logger = logging.getLogger(__name__)


# ── Pydantic schemas ─────────────────────────────────────────────────

class CreateBARequest(BaseModel):
    task_id: int
    title:   Optional[str] = "Berita Acara Sidang"


class QAItem(BaseModel):
    id:       int
    question: str
    answer:   str


class SaveQARequest(BaseModel):
    qa_list: list[QAItem]
    title:   Optional[str] = None


class PromptUpdateRequest(BaseModel):
    prompt_text: str


# ── Helpers ──────────────────────────────────────────────────────────

async def _run_process_async(ba_id: int) -> None:
    await run_in_threadpool(process_berita_acara, ba_id)


def _assert_ba_owner(ba: BeritaAcara, user: User) -> None:
    if user.role == "admin":
        return
    if ba.user_id is None or ba.user_id != user.id:
        raise HTTPException(status_code=403, detail="Akses ditolak.")


def _ba_to_dict(ba: BeritaAcara, include_qa: bool = False) -> dict:
    d = {
        "id":              ba.id,
        "task_id":         ba.task_id,
        "user_id":         ba.user_id,
        "title":           ba.title,
        "status":          ba.status,
        "error_message":   ba.error_message,
        "model_used":      ba.model_used,
        "processing_time": ba.processing_time,
        "created_at":      ba.created_at.isoformat() if ba.created_at else None,
        "updated_at":      ba.updated_at.isoformat() if ba.updated_at else None,
        "billed_amount":   ba.billed_amount,   # tambahkan field ini ke model
    }
    if include_qa:
        d["qa_list"] = get_ba_qa_decrypted(ba)
    return d


# ================================================================
# POST /api/berita-acara — Buat Berita Acara baru
# ================================================================
@router.post("/berita-acara")
async def create_berita_acara(
    payload:          CreateBARequest,
    background_tasks: BackgroundTasks,
    db:               Session = Depends(get_db),
    current_user:     User    = Depends(get_current_user),
):
    # 1. Validasi task
    task = db.query(TranskripsiTask).filter(
        TranskripsiTask.id == payload.task_id
    ).first()

    if not task:
        raise HTTPException(status_code=404, detail="Task tidak ditemukan.")
    if task.status != "completed":
        raise HTTPException(
            status_code=400,
            detail="Task belum selesai. Berita Acara hanya bisa dibuat dari task yang completed.",
        )

    # Cek kepemilikan task (admin bypass)
    if current_user.role != "admin" and task.user_id != current_user.id:
        raise HTTPException(status_code=403, detail="Akses ditolak.")

    # 2. Hitung biaya BA
    ba_rate = get_ba_rate(db)

    # 3. Potong saldo user
    try:
        deduct_balance(
            db=db,
            user_id=current_user.id,
            amount=ba_rate,
            service_type="ba",
            description=f"Pembuatan Berita Acara untuk task {payload.task_id}"
        )
    except ValueError as e:
        raise HTTPException(status_code=402, detail=str(e))

    # 4. Ambil prompt snapshot
    prompt_snapshot = get_active_prompt(db)

    # 5. Buat BA record (dengan mencatat jumlah yang ditagih)
    ba = BeritaAcara(
        task_id       = task.id,
        user_id       = current_user.id,
        title         = payload.title or "Berita Acara Sidang",
        status        = "pending",
        prompt_used   = prompt_snapshot,
        billed_amount = ba_rate,   # simpan untuk keperluan refund jika gagal
    )
    db.add(ba)
    db.commit()
    db.refresh(ba)

    # 6. Jalankan proses background
    background_tasks.add_task(_run_process_async, ba.id)

    logger.info(
        "[BA] BeritaAcara #%d dibuat oleh user %d untuk task %d, biaya=%d",
        ba.id, current_user.id, task.id, ba_rate,
    )

    return {
        "success":      True,
        "ba_id":        ba.id,
        "status":       "pending",
        "billed_amount": ba_rate,
        "balance":      current_user.balance,   # saldo setelah pemotongan
    }


# ================================================================
# GET /api/berita-acara/by-task/{task_id}
# ================================================================
@router.get("/berita-acara/by-task/{task_id}")
def list_ba_by_task(
    task_id:      int,
    db:           Session = Depends(get_db),
    current_user: User    = Depends(get_current_user),
):
    query = db.query(BeritaAcara).filter(BeritaAcara.task_id == task_id)
    if current_user.role != "admin":
        query = query.filter(BeritaAcara.user_id == current_user.id)

    items = query.order_by(BeritaAcara.created_at.desc()).all()
    return {"items": [_ba_to_dict(ba) for ba in items]}


# ================================================================
# GET /api/berita-acara/{ba_id}
# ================================================================
@router.get("/berita-acara/{ba_id}")
def get_berita_acara(
    ba_id:        int,
    db:           Session = Depends(get_db),
    current_user: User    = Depends(get_current_user),
):
    ba = db.query(BeritaAcara).filter(BeritaAcara.id == ba_id).first()
    if not ba:
        raise HTTPException(status_code=404, detail="Berita Acara tidak ditemukan.")

    _assert_ba_owner(ba, current_user)
    return _ba_to_dict(ba, include_qa=True)


# ================================================================
# PATCH /api/berita-acara/{ba_id} — Simpan edit Q&A
# ================================================================
@router.patch("/berita-acara/{ba_id}")
def update_berita_acara(
    ba_id:        int,
    payload:      SaveQARequest,
    db:           Session = Depends(get_db),
    current_user: User    = Depends(get_current_user),
):
    ba = db.query(BeritaAcara).filter(BeritaAcara.id == ba_id).first()
    if not ba:
        raise HTTPException(status_code=404, detail="Berita Acara tidak ditemukan.")

    _assert_ba_owner(ba, current_user)

    if ba.status not in ("completed",):
        raise HTTPException(
            status_code=400,
            detail="Hanya BeritaAcara yang sudah selesai yang bisa diedit.",
        )

    qa_dicts = [item.model_dump() for item in payload.qa_list]
    # Re-assign ID urut agar konsisten
    for i, item in enumerate(qa_dicts, start=1):
        item["id"] = i

    if payload.title:
        ba.title = payload.title

    save_qa_edits(db, ba, qa_dicts)
    logger.info("[BA] BeritaAcara #%d diedit oleh user %d.", ba_id, current_user.id)
    return {"success": True, "message": "Berita Acara berhasil disimpan."}


# ================================================================
# DELETE /api/berita-acara/{ba_id}
# ================================================================
@router.delete("/berita-acara/{ba_id}")
def delete_berita_acara(
    ba_id:        int,
    db:           Session = Depends(get_db),
    current_user: User    = Depends(get_current_user),
):
    ba = db.query(BeritaAcara).filter(BeritaAcara.id == ba_id).first()
    if not ba:
        raise HTTPException(status_code=404, detail="Berita Acara tidak ditemukan.")

    _assert_ba_owner(ba, current_user)

    # Jika BA sudah ditagih dan belum di-refund (misal status masih pending/processing/failed)
    # kita bisa memberikan refund opsional saat dihapus. Namun untuk sederhananya, kita tidak refund.
    db.delete(ba)
    db.commit()
    return {"success": True, "message": f"Berita Acara #{ba_id} berhasil dihapus."}


# ================================================================
# Admin: GET /api/admin/ba-prompt
# ================================================================
@router.get("/admin/ba-prompt")
def get_ba_prompt(
    db:            Session = Depends(get_db),
    current_admin: User    = Depends(get_current_admin),
):
    prompt = get_active_prompt(db)
    row    = db.query(BeritaAcaraPrompt).filter(
        BeritaAcaraPrompt.name == "default"
    ).first()
    return {
        "prompt_text": prompt,
        "is_default":  row is None,
        "updated_at":  row.updated_at.isoformat() if row and row.updated_at else None,
    }


# ================================================================
# Admin: POST /api/admin/ba-prompt
# ================================================================
@router.post("/admin/ba-prompt")
def save_ba_prompt(
    payload:       PromptUpdateRequest,
    db:            Session = Depends(get_db),
    current_admin: User    = Depends(get_current_admin),
):
    if not payload.prompt_text.strip():
        raise HTTPException(status_code=400, detail="Prompt tidak boleh kosong.")
    if "{transcript}" not in payload.prompt_text:
        raise HTTPException(
            status_code=400,
            detail="Prompt harus mengandung placeholder {transcript}.",
        )

    row = upsert_prompt(db, payload.prompt_text.strip(), current_admin.id)
    logger.info("[BA] Prompt diupdate oleh admin ID %d.", current_admin.id)
    return {
        "success":    True,
        "updated_at": row.updated_at.isoformat() if row.updated_at else None,
    }


# ================================================================
# Admin: GET /api/admin/ba-prompt/default — kembalikan default prompt
# ================================================================
@router.get("/admin/ba-prompt/default")
def get_default_prompt(
    current_admin: User = Depends(get_current_admin),
):
    return {"prompt_text": DEFAULT_PROMPT}