"""General Affairs router — operators, jadwal, absensi endpoints."""

from datetime import date

from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile, status
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.database import get_db
from app.dependencies import get_current_user, get_spbu_access
from app.models.user import User
from app.schemas.general_affairs import (
    AbsensiResponse,
    AbsensiSlotResponse,
    AbsensiSlotOperator,
    HousekeepingResponse,
    JadwalBulkCreate,
    JadwalResponse,
    OperatorResponse,
    SaprasResponse,
)
from app.services import general_affairs_service

router = APIRouter()


# ── Operators ─────────────────────────────────────────────────────────────────

@router.get("/spbus/{spbu_id}/operators", response_model=list[OperatorResponse])
async def list_operators(
    spbu_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> list[OperatorResponse]:
    ops = await general_affairs_service.list_operators(db, spbu_id)
    return [OperatorResponse(**op) for op in ops]


# ── Jadwal ────────────────────────────────────────────────────────────────────

@router.get("/spbus/{spbu_id}/jadwal", response_model=list[JadwalResponse])
async def list_jadwal(
    spbu_id: int,
    start: date,
    end: date,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> list[JadwalResponse]:
    rows = await general_affairs_service.list_jadwal(db, spbu_id, start, end)
    return [
        JadwalResponse(
            id=r.id,
            spbu_id=r.spbu_id,
            user_id=r.user_id,
            shift_id=r.shift_id,
            tanggal=r.tanggal,
            user_nama=r.user.name if r.user else None,
            shift_nama=r.shift.nama if r.shift else None,
        )
        for r in rows
    ]


@router.post("/spbus/{spbu_id}/jadwal", status_code=status.HTTP_201_CREATED)
async def create_jadwal(
    spbu_id: int,
    data: JadwalBulkCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    try:
        created = await general_affairs_service.create_jadwal_bulk(
            db, spbu_id, data.items, current_user.id
        )
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    return {"message": f"{len(created)} jadwal berhasil dibuat"}


@router.delete("/spbus/{spbu_id}/jadwal/{jadwal_id}", status_code=status.HTTP_200_OK)
async def delete_jadwal(
    spbu_id: int,
    jadwal_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    deleted = await general_affairs_service.delete_jadwal(db, jadwal_id, spbu_id)
    if not deleted:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Jadwal tidak ditemukan")
    return {"message": "Jadwal berhasil dihapus"}


# ── Absensi ───────────────────────────────────────────────────────────────────

@router.get("/spbus/{spbu_id}/absensi/slot", response_model=AbsensiSlotResponse)
async def get_absensi_slot(
    spbu_id: int,
    tanggal: date,
    shift_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> AbsensiSlotResponse:
    result = await general_affairs_service.get_absensi_slot(db, spbu_id, shift_id, tanggal)
    absensi = result["absensi"]
    absensi_resp = None
    if absensi:
        absensi_resp = AbsensiResponse(
            id=absensi.id,
            spbu_id=absensi.spbu_id,
            shift_id=absensi.shift_id,
            tanggal=absensi.tanggal,
            foto_url=absensi.foto_url,
            foto_eksif_waktu=absensi.foto_eksif_waktu,
            status=absensi.status,
            uploaded_by_nama=absensi.uploaded_by.name if absensi.uploaded_by else None,
            uploaded_at=absensi.uploaded_at,
            reviewed_by_nama=absensi.reviewed_by.name if absensi.reviewed_by else None,
            reviewed_at=absensi.reviewed_at,
            shift_nama=absensi.shift.nama if absensi.shift else None,
        )
    return AbsensiSlotResponse(
        absensi=absensi_resp,
        operators=[AbsensiSlotOperator(**op) for op in result["operators"]],
    )


@router.get("/spbus/{spbu_id}/absensi", response_model=list[AbsensiResponse])
async def list_absensi(
    spbu_id: int,
    start: date,
    end: date,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> list[AbsensiResponse]:
    rows = await general_affairs_service.list_absensi(db, spbu_id, start, end)
    return [
        AbsensiResponse(
            id=r.id,
            spbu_id=r.spbu_id,
            shift_id=r.shift_id,
            tanggal=r.tanggal,
            foto_url=r.foto_url,
            status=r.status,
            uploaded_by_nama=r.uploaded_by.name if r.uploaded_by else None,
            uploaded_at=r.uploaded_at,
            reviewed_by_nama=r.reviewed_by.name if r.reviewed_by else None,
            reviewed_at=r.reviewed_at,
            shift_nama=r.shift.nama if r.shift else None,
        )
        for r in rows
    ]


@router.post("/spbus/{spbu_id}/absensi", status_code=status.HTTP_201_CREATED)
async def upload_absensi(
    spbu_id: int,
    shift_id: int = Form(...),
    tanggal: date = Form(...),
    foto_eksif_waktu: str | None = Form(None),
    foto: UploadFile = File(...),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    file_bytes = await foto.read()
    if len(file_bytes) == 0:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="File kosong")
    try:
        absensi = await general_affairs_service.upload_absensi(
            db, spbu_id, shift_id, tanggal,
            file_bytes, foto.filename or "absensi.jpg", current_user.id,
            foto_eksif_waktu,
        )
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
    return {"message": "Foto absensi berhasil diupload", "id": absensi.id, "foto_url": absensi.foto_url}


@router.patch("/spbus/{spbu_id}/absensi/{absensi_id}/approve")
async def approve_absensi(
    spbu_id: int,
    absensi_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    try:
        absensi = await general_affairs_service.approve_absensi(db, spbu_id, absensi_id, current_user.id)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
    return {"message": "Absensi diapprove", "id": absensi.id, "status": absensi.status}


@router.delete("/spbus/{spbu_id}/absensi/{absensi_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_absensi(
    spbu_id: int,
    absensi_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> None:
    try:
        await general_affairs_service.delete_absensi(db, spbu_id, absensi_id)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))


# ── Housekeeping ───────────────────────────────────────────────────────────────

def _hk_response(hk) -> HousekeepingResponse:
    return HousekeepingResponse(
        id=hk.id,
        spbu_id=hk.spbu_id,
        shift_id=hk.shift_id,
        tanggal=hk.tanggal,
        status=hk.status,
        uploaded_by_nama=hk.uploaded_by.name if hk.uploaded_by else None,
        uploaded_at=hk.uploaded_at,
        reviewed_by_nama=hk.reviewed_by.name if hk.reviewed_by else None,
        reviewed_at=hk.reviewed_at,
        items=hk.items,
        fotos=hk.fotos,
    )


@router.get("/spbus/{spbu_id}/housekeeping", response_model=list[HousekeepingResponse])
async def list_housekeeping(
    spbu_id: int,
    start: date,
    end: date,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> list[HousekeepingResponse]:
    rows = await general_affairs_service.get_housekeeping_list(db, spbu_id, start, end)
    return [_hk_response(r) for r in rows]


@router.get("/spbus/{spbu_id}/housekeeping/slot", response_model=HousekeepingResponse | None)
async def get_housekeeping_slot(
    spbu_id: int,
    tanggal: date,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    hk = await general_affairs_service.get_housekeeping_slot(db, spbu_id, tanggal)
    return _hk_response(hk) if hk else None


@router.post("/spbus/{spbu_id}/housekeeping", status_code=status.HTTP_201_CREATED)
async def submit_housekeeping(
    spbu_id: int,
    tanggal: date = Form(...),
    items: str = Form(default="[]"),  # JSON: ["desc1", "desc2"]
    submitted: bool = Form(default=False),
    fotos: list[UploadFile] = File(default=[]),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    import json
    try:
        item_list: list[str] = json.loads(items)
    except Exception:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="items harus JSON array string")

    files = [(await f.read(), f.filename or "foto.jpg") for f in fotos if f.filename]

    try:
        hk = await general_affairs_service.submit_housekeeping(
            db, spbu_id, tanggal, current_user.id,
            item_list, files, submitted=submitted,
        )
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    return {"message": "Housekeeping berhasil disimpan", "id": hk.id, "status": hk.status}


@router.patch("/spbus/{spbu_id}/housekeeping/{hk_id}/approve")
async def approve_housekeeping(
    spbu_id: int,
    hk_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    try:
        hk = await general_affairs_service.approve_housekeeping(db, spbu_id, hk_id, current_user.id)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
    return {"message": "Housekeeping diapprove", "id": hk.id, "status": hk.status}


@router.patch("/spbus/{spbu_id}/housekeeping/{hk_id}/back-to-draft")
async def back_to_draft_housekeeping(
    spbu_id: int,
    hk_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    try:
        hk = await general_affairs_service.back_to_draft_housekeeping(db, spbu_id, hk_id)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
    return {"message": "Housekeeping dikembalikan ke draft", "id": hk.id, "status": hk.status}


@router.delete("/spbus/{spbu_id}/housekeeping/{hk_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_housekeeping(
    spbu_id: int,
    hk_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> None:
    try:
        await general_affairs_service.delete_housekeeping(db, spbu_id, hk_id)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))


# ── Sapras ────────────────────────────────────────────────────────────────────

def _sapras_response(s) -> SaprasResponse:
    return SaprasResponse(
        id=s.id,
        spbu_id=s.spbu_id,
        tanggal=s.tanggal,
        catatan=s.catatan,
        status=s.status,
        uploaded_by_nama=s.uploaded_by.name if s.uploaded_by else None,
        uploaded_at=s.uploaded_at,
        reviewed_by_nama=s.reviewed_by.name if s.reviewed_by else None,
        reviewed_at=s.reviewed_at,
        items=s.items,
    )


@router.get("/spbus/{spbu_id}/sapras", response_model=list[SaprasResponse])
async def list_sapras(
    spbu_id: int,
    start: date,
    end: date,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> list[SaprasResponse]:
    rows = await general_affairs_service.get_sapras_list(db, spbu_id, start, end)
    return [_sapras_response(r) for r in rows]


@router.get("/spbus/{spbu_id}/sapras/slot", response_model=SaprasResponse | None)
async def get_sapras_slot(
    spbu_id: int,
    tanggal: date,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    s = await general_affairs_service.get_sapras_slot(db, spbu_id, tanggal)
    return _sapras_response(s) if s else None


@router.post("/spbus/{spbu_id}/sapras", status_code=status.HTTP_201_CREATED)
async def submit_sapras(
    spbu_id: int,
    tanggal: date = Form(...),
    catatan: str | None = Form(None),
    submitted: bool = Form(default=False),
    items: str = Form(default="[]"),  # JSON: [{kegiatan: "..."}]
    fotos_sebelum: list[UploadFile] = File(default=[]),
    fotos_sesudah: list[UploadFile] = File(default=[]),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    import json
    try:
        items_parsed: list[dict] = json.loads(items)
    except Exception:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="items harus JSON array")

    # Build per-item file tuples aligned by index
    sebelum_map: dict[int, tuple[bytes, str]] = {}
    for i, f in enumerate(fotos_sebelum):
        if f.filename:
            content = await f.read()
            if content:
                sebelum_map[i] = (content, f.filename)

    sesudah_map: dict[int, tuple[bytes, str]] = {}
    for i, f in enumerate(fotos_sesudah):
        if f.filename:
            content = await f.read()
            if content:
                sesudah_map[i] = (content, f.filename)

    items_files = [
        {
            "kegiatan": item.get("kegiatan", ""),
            "file_sebelum": sebelum_map.get(i),
            "file_sesudah": sesudah_map.get(i),
        }
        for i, item in enumerate(items_parsed)
    ]

    try:
        s = await general_affairs_service.submit_sapras(
            db, spbu_id, tanggal, current_user.id,
            catatan, items_files, submitted=submitted,
        )
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
    return {"message": "Sapras berhasil disimpan", "id": s.id, "status": s.status}


@router.patch("/spbus/{spbu_id}/sapras/{sapras_id}/back-to-draft")
async def back_to_draft_sapras(
    spbu_id: int,
    sapras_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    try:
        s = await general_affairs_service.back_to_draft_sapras(db, spbu_id, sapras_id)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
    return {"message": "Sapras dikembalikan ke draft", "id": s.id, "status": s.status}


@router.delete("/spbus/{spbu_id}/sapras/{sapras_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_sapras(
    spbu_id: int,
    sapras_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> None:
    try:
        await general_affairs_service.delete_sapras(db, spbu_id, sapras_id)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
