"""
routes_transkripsi.py — Endpoint transkripsi untuk user.

Perubahan dari versi sebelumnya:
- Semua endpoint wajib login (get_current_user).
- create_task() menerima user_id agar task tercatat milik user yang upload.
- GET /api/tasks hanya mengembalikan task milik user yang sedang login.
- GET /api/status/{task_id} memverifikasi kepemilikan task.
- DELETE /api/tasks/{task_id} memverifikasi kepemilikan task.
- Result dikembalikan lewat task_formatter (sudah didekripsi + court mode).
- BILLING: setiap upload akan mengecek saldo user, memotong biaya transkripsi
  berdasarkan durasi audio, dan melakukan refund jika terjadi error sebelum
  task berhasil masuk antrian.

[PATCH v2] Tiga opsi hapus granular per task:
- DELETE /api/transkripsi/{task_id}/audio   — hapus file audio saja, transkripsi tetap
- DELETE /api/transkripsi/{task_id}/result  — hapus hasil transkripsi saja, audio tetap  ← BARU
- DELETE /api/transkripsi/{task_id}         — hapus keduanya (task + audio + hasil)
- DELETE /api/tasks/{task_id}               — alias lama, tetap dipertahankan
"""

import logging

from fastapi import APIRouter, UploadFile, File, Form, Depends, HTTPException, BackgroundTasks, Query
from sqlalchemy.orm import Session

from app.core.database import get_db
from app.models.transkripsi import TranskripsiTask
from app.services.task_service import create_task, get_task_by_id
from app.services.transcription_service import process_task
from app.services.auth_service import get_current_user
from app.utils.file_utils import save_upload_file, delete_file
from app.utils.whisper_worker import run_in_threadpool
from app.utils.task_formatter import task_to_response
from app.core.config import AVAILABLE_MODELS, ENGINE_LOCAL, ENGINE_API
from app.models.user import User

# --- Billing imports ---
from app.utils.billing import (
    get_audio_duration,
    get_transcription_rate,
    calculate_transcription_cost,
    deduct_balance,
    refund_balance,
)

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


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


def _assert_task_owner(task: TranskripsiTask, current_user: User) -> None:
    """
    Pastikan current_user adalah pemilik task.
    Admin dibebaskan dari pengecekan ini.
    Melempar 403 jika bukan pemilik.
    """
    if current_user.role == "admin":
        return
    if task.user_id is None or task.user_id != current_user.id:
        raise HTTPException(
            status_code=403,
            detail="Anda tidak memiliki akses ke task ini.",
        )


def _delete_task_logic(task: TranskripsiTask, db: Session, current_user: User) -> dict:
    """
    Shared logic untuk menghapus task beserta file audio dan hasil transkripsi.
    Dipanggil oleh DELETE /api/tasks/{task_id} dan DELETE /api/transkripsi/{task_id}.

    Aturan:
    - Task pending/processing tidak boleh dihapus (worker mungkin sedang berjalan).
      Jika task nyangkut karena server restart, startup_recovery sudah mengubahnya
      menjadi 'failed' sehingga endpoint ini bisa berjalan normal.
    - Admin bisa hapus task siapapun. User hanya bisa hapus task miliknya.
    """
    _assert_task_owner(task, current_user)

    if task.status in ("pending", "processing"):
        raise HTTPException(
            status_code=409,
            detail=(
                f"Task #{task.id} masih berstatus '{task.status}' dan tidak bisa dihapus. "
                "Jika task ini nyangkut, coba restart server — sistem akan otomatis "
                "mengubah status task menjadi 'failed' sehingga bisa dihapus."
            ),
        )

    delete_file(task.audio_file)
    db.delete(task)
    db.commit()

    logger.info("[Delete] Task %d dihapus oleh user %d.", task.id, current_user.id)
    return {"success": True, "message": f"Task #{task.id} beserta semua datanya berhasil dihapus."}


# ================================================================
# POST /api/upload
# ================================================================
@router.post("/upload")
async def upload_audio(
    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),
):
    # Validasi engine
    if engine not in (ENGINE_LOCAL, ENGINE_API):
        raise HTTPException(
            status_code=400,
            detail=f"Engine tidak valid. Pilihan: {ENGINE_LOCAL}, {ENGINE_API}",
        )

    # Validasi model hanya untuk engine lokal
    # Engine API menggunakan whisper-1 secara otomatis
    if engine == ENGINE_API:
        model_type = "openai/whisper-1"
    elif model_type not in AVAILABLE_MODELS:
        raise HTTPException(
            status_code=400,
            detail=f"Model tidak valid. Pilihan: {AVAILABLE_MODELS}",
        )

    # 1. Simpan file sementara
    file_path = await save_upload_file(file)

    # 2. Hitung durasi audio & biaya
    try:
        duration = get_audio_duration(file_path)
    except Exception as e:
        delete_file(file_path)
        raise HTTPException(
            status_code=400,
            detail=(
                f"Tidak dapat membaca durasi audio: {str(e)}. "
                "Pastikan file audio valid dan ffmpeg terinstal."
            ),
        )

    rate_per_minute = get_transcription_rate(db)
    cost = calculate_transcription_cost(duration, rate_per_minute)

    # 3. Potong saldo user
    try:
        deduct_balance(
            db=db,
            user_id=current_user.id,
            amount=cost,
            service_type="transcription",
            description=f"Transkripsi file {file.filename} (durasi {duration:.1f} detik)",
        )
    except ValueError as e:
        delete_file(file_path)
        raise HTTPException(status_code=402, detail=str(e))

    # 4. Buat task di database
    try:
        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,
        )
    except Exception as exc:
        # Gagal membuat task → refund biaya yang sudah dipotong
        refund_balance(
            db=db,
            user_id=current_user.id,
            amount=cost,
            service_type="transcription",
            description=f"Refund karena gagal membuat task untuk file {file.filename}",
        )
        delete_file(file_path)
        logger.error("[Upload] Gagal membuat task di DB: %s", exc, exc_info=True)
        raise HTTPException(
            status_code=500,
            detail="Gagal membuat task transkripsi. Silakan coba lagi.",
        ) from exc

    # 5. Jalankan transkripsi di background
    background_tasks.add_task(_run_transcription_async, task.id)

    logger.info(
        "[Upload] Task %d dibuat oleh user %d (engine=%s, model=%s, court=%s, biaya=%d)",
        task.id, current_user.id, engine, model_type, is_court_mode, cost,
    )

    return {
        "success":   True,
        "task_id":   task.id,
        "task_uuid": task.task_uuid,
        "cost":      cost,
        "balance":   current_user.balance,
        "message":   "File berhasil diupload. Transkripsi sedang berjalan.",
    }


# ================================================================
# GET /api/status/{task_id}
# ================================================================
@router.get("/status/{task_id}")
def get_status(
    task_id:      int,
    db:           Session = Depends(get_db),
    current_user: User    = Depends(get_current_user),
):
    task = get_task_by_id(db, task_id)
    if not task:
        raise HTTPException(status_code=404, detail="Task tidak ditemukan.")

    _assert_task_owner(task, current_user)

    return task_to_response(task)


# ================================================================
# GET /api/tasks — daftar task milik user yang login
# ================================================================
@router.get("/tasks")
def list_tasks(
    limit:        int     = Query(default=20, ge=1, le=100),
    offset:       int     = Query(default=0,  ge=0),
    status:       str     = Query(default=None),
    db:           Session = Depends(get_db),
    current_user: User    = Depends(get_current_user),
):
    valid_statuses = {"pending", "processing", "completed", "failed", "cancelled"}
    if status and status not in valid_statuses:
        raise HTTPException(
            status_code=400,
            detail=f"Status tidak valid. Pilihan: {sorted(valid_statuses)}",
        )

    query = db.query(TranskripsiTask)
    if current_user.role != "admin":
        query = query.filter(TranskripsiTask.user_id == current_user.id)

    if status:
        query = query.filter(TranskripsiTask.status == status)

    total = query.count()
    tasks = (
        query
        .order_by(TranskripsiTask.created_at.desc())
        .offset(offset)
        .limit(limit)
        .all()
    )

    return {
        "tasks":  [task_to_response(t) for t in tasks],
        "total":  total,
        "limit":  limit,
        "offset": offset,
    }


# ================================================================
# DELETE /api/tasks/{task_id}
# Endpoint lama — tetap dipertahankan untuk kompatibilitas.
# ================================================================
@router.delete("/tasks/{task_id}")
def delete_task(
    task_id:      int,
    db:           Session = Depends(get_db),
    current_user: User    = Depends(get_current_user),
):
    task = get_task_by_id(db, task_id)
    if not task:
        raise HTTPException(status_code=404, detail="Task tidak ditemukan.")

    return _delete_task_logic(task, db, current_user)


# ================================================================
# DELETE /api/transkripsi/{task_id}
# Hapus task + file audio + hasil transkripsi sekaligus (semua data).
# ================================================================
@router.delete("/transkripsi/{task_id}")
def delete_own_task(
    task_id:      int,
    db:           Session = Depends(get_db),
    current_user: User    = Depends(get_current_user),
):
    task = get_task_by_id(db, task_id)
    if not task:
        raise HTTPException(status_code=404, detail="Task tidak ditemukan.")

    return _delete_task_logic(task, db, current_user)


# ================================================================
# DELETE /api/transkripsi/{task_id}/audio
# Hapus file audio dari disk tanpa menghapus record task atau hasil transkripsi.
# ================================================================
@router.delete("/transkripsi/{task_id}/audio")
def delete_audio_only(
    task_id:      int,
    db:           Session = Depends(get_db),
    current_user: User    = Depends(get_current_user),
):
    """Hapus file audio dari disk. Record task dan hasil transkripsi TETAP tersimpan."""
    task = get_task_by_id(db, task_id)
    if not task:
        raise HTTPException(status_code=404, detail="Task tidak ditemukan.")

    _assert_task_owner(task, current_user)

    if task.status in ("pending", "processing"):
        raise HTTPException(
            status_code=409,
            detail=f"Task #{task_id} masih berstatus '{task.status}', tidak bisa menghapus file audio.",
        )

    from pathlib import Path

    file_deleted = False
    if task.audio_file:
        p = Path(task.audio_file)
        if p.exists():
            delete_file(task.audio_file)
            file_deleted = True
        task.audio_file = None
        db.commit()

    logger.info("[Delete Audio] Task %d: file audio dihapus oleh user %d.", task_id, current_user.id)
    return {
        "success":      True,
        "file_deleted": file_deleted,
        "message":      "File audio berhasil dihapus. Hasil transkripsi tetap tersimpan.",
    }


# ================================================================
# DELETE /api/transkripsi/{task_id}/result
# Hapus hasil transkripsi (result, segments, partial) tanpa menyentuh
# file audio atau menghapus record task dari database.
# ================================================================
@router.delete("/transkripsi/{task_id}/result")
def delete_result_only(
    task_id:      int,
    db:           Session = Depends(get_db),
    current_user: User    = Depends(get_current_user),
):
    """
    Hapus hasil transkripsi saja.
    File audio tetap ada di server. Record task tetap tersimpan di database.
    Berguna jika user ingin membersihkan teks sensitif tanpa menghapus file audio.
    """
    task = get_task_by_id(db, task_id)
    if not task:
        raise HTTPException(status_code=404, detail="Task tidak ditemukan.")

    _assert_task_owner(task, current_user)

    if task.status in ("pending", "processing"):
        raise HTTPException(
            status_code=409,
            detail=f"Task #{task_id} masih berstatus '{task.status}', tidak bisa menghapus hasil transkripsi.",
        )

    # Bersihkan semua kolom hasil transkripsi
    task.result         = None
    task.partial_result = ""
    task.segments_json  = "[]"
    # Tandai status sebagai 'failed' agar tidak muncul sebagai completed tanpa isi,
    # tapi gunakan status khusus jika ada. Di sini kita pakai 'deleted_result'
    # yang aman karena tidak diproses worker. Jika kolom status tidak mendukung
    # nilai ini, gunakan 'failed' saja.
    # Pilihan konservatif: biarkan status tetap, cukup kosongkan result.
    db.commit()

    logger.info("[Delete Result] Task %d: hasil transkripsi dihapus oleh user %d.", task_id, current_user.id)
    return {
        "success": True,
        "message": "Hasil transkripsi berhasil dihapus. File audio dan riwayat task tetap tersimpan.",
    }