import sqlite3

from fastapi import Depends, FastAPI, HTTPException, status

from app.database import dapatkan_koneksi
from app.models import DetailGalat, TugasBuat, TugasPerbarui, TugasTampil

app = FastAPI(title="API Manajemen Tugas", version="0.4.0")


def baris_ke_tugas(baris: sqlite3.Row) -> dict:
    return {
        "id": baris["id"],
        "judul": baris["judul"],
        "selesai": bool(baris["selesai"]),
    }


@app.get("/health")
def health() -> dict[str, str]:
    return {"status": "ok"}


@app.get("/tugas", response_model=list[TugasTampil])
def daftar_tugas(koneksi: sqlite3.Connection = Depends(dapatkan_koneksi)) -> list[dict]:
    baris_semua = koneksi.execute(
        "SELECT id, judul, selesai FROM tugas ORDER BY id"
    ).fetchall()
    return [baris_ke_tugas(baris) for baris in baris_semua]


@app.post(
    "/tugas",
    response_model=TugasTampil,
    status_code=status.HTTP_201_CREATED,
    responses={422: {"model": DetailGalat, "description": "Body tidak valid"}},
)
def buat_tugas(
    payload: TugasBuat, koneksi: sqlite3.Connection = Depends(dapatkan_koneksi)
) -> dict:
    with koneksi:
        kursor = koneksi.execute(
            "INSERT INTO tugas (judul, selesai) VALUES (?, ?)",
            (payload.judul, 0),
        )
    baris = koneksi.execute(
        "SELECT id, judul, selesai FROM tugas WHERE id = ?",
        (kursor.lastrowid,),
    ).fetchone()
    return baris_ke_tugas(baris)


@app.get(
    "/tugas/{tugas_id}",
    response_model=TugasTampil,
    responses={404: {"model": DetailGalat, "description": "Tugas tidak ditemukan"}},
)
def ambil_tugas(
    tugas_id: int, koneksi: sqlite3.Connection = Depends(dapatkan_koneksi)
) -> dict:
    baris = koneksi.execute(
        "SELECT id, judul, selesai FROM tugas WHERE id = ?",
        (tugas_id,),
    ).fetchone()
    if baris is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"tugas dengan id {tugas_id} tidak ditemukan",
        )
    return baris_ke_tugas(baris)


@app.patch(
    "/tugas/{tugas_id}",
    response_model=TugasTampil,
    responses={
        400: {"model": DetailGalat, "description": "Body kosong"},
        404: {"model": DetailGalat, "description": "Tugas tidak ditemukan"},
        422: {"model": DetailGalat, "description": "Body tidak valid"},
    },
)
def perbarui_tugas(
    tugas_id: int,
    payload: TugasPerbarui,
    koneksi: sqlite3.Connection = Depends(dapatkan_koneksi),
) -> dict:
    baris = koneksi.execute(
        "SELECT id, judul, selesai FROM tugas WHERE id = ?",
        (tugas_id,),
    ).fetchone()
    if baris is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"tugas dengan id {tugas_id} tidak ditemukan",
        )

    pembaruan = payload.model_dump(exclude_unset=True)
    if not pembaruan:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="minimal satu field (judul atau selesai) harus dikirim",
        )

    with koneksi:
        if "judul" in pembaruan:
            koneksi.execute(
                "UPDATE tugas SET judul = ? WHERE id = ?",
                (pembaruan["judul"], tugas_id),
            )
        if "selesai" in pembaruan:
            koneksi.execute(
                "UPDATE tugas SET selesai = ? WHERE id = ?",
                (int(pembaruan["selesai"]), tugas_id),
            )

    baris = koneksi.execute(
        "SELECT id, judul, selesai FROM tugas WHERE id = ?",
        (tugas_id,),
    ).fetchone()
    return baris_ke_tugas(baris)


@app.delete(
    "/tugas/{tugas_id}",
    status_code=status.HTTP_204_NO_CONTENT,
    responses={404: {"model": DetailGalat, "description": "Tugas tidak ditemukan"}},
)
def hapus_tugas(
    tugas_id: int, koneksi: sqlite3.Connection = Depends(dapatkan_koneksi)
) -> None:
    with koneksi:
        kursor = koneksi.execute(
            "DELETE FROM tugas WHERE id = ?",
            (tugas_id,),
        )
    if kursor.rowcount == 0:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"tugas dengan id {tugas_id} tidak ditemukan",
        )
