"""Router for penyetoran (per-shift cash deposit) endpoints."""

from datetime import date
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, Query, UploadFile, File, 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.penyetoran import (
    BatchReviewRequest,
    DailySummary,
    PenyetoranBatchCreate,
    PenyetoranBatchResponse,
    PenyetoranResponse,
    PenyetoranUpdate,
)
from app.services import penyetoran_service

router = APIRouter(
    prefix="/spbus/{spbu_id}/penyetoran",
    tags=["penyetoran"],
)


def _service_error(e: ValueError | PermissionError) -> HTTPException:
    """Convert service-layer ValueError → 400 and PermissionError → 403."""
    if isinstance(e, PermissionError):
        return HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=str(e))
    return HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))


# ---------------------------------------------------------------------------
# Penyetoran list & detail
# NOTE: /batches and /summary/{tanggal} MUST appear before /{penyetoran_id}
# to avoid FastAPI treating those path segments as integer path params.
# ---------------------------------------------------------------------------

@router.get("", response_model=dict)
async def list_penyetoran(
    spbu_id: int,
    skip: int = Query(default=0, ge=0),
    limit: int = Query(default=50, ge=1, le=200),
    tanggal_from: Optional[date] = Query(default=None),
    tanggal_to: Optional[date] = Query(default=None),
    status_filter: Optional[str] = Query(default=None, alias="status"),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    """
    List penyetoran records for an SPBU (newest first).
    Requires: penyetoran:view permission.
    """
    try:
        rows, total = await penyetoran_service.list_penyetoran(
            db, spbu_id, skip, limit,
            tanggal_from=tanggal_from,
            tanggal_to=tanggal_to,
            status=status_filter,
        )
    except (ValueError, PermissionError) as e:
        raise _service_error(e)
    return {
        "data": [r.model_dump() for r in rows],
        "meta": {"total": total, "page": skip // limit + 1, "per_page": limit},
    }


@router.get("/batches", response_model=dict)
async def list_batches(
    spbu_id: int,
    skip: int = Query(default=0, ge=0),
    limit: int = Query(default=50, ge=1, le=200),
    status_filter: Optional[str] = Query(default=None, alias="status"),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    """
    List penyetoran batches for an SPBU (newest first).
    Requires: penyetoran:view permission.
    """
    try:
        rows, total = await penyetoran_service.list_batches(
            db, spbu_id, skip, limit, status=status_filter
        )
    except (ValueError, PermissionError) as e:
        raise _service_error(e)
    return {
        "data": [r.model_dump() for r in rows],
        "meta": {"total": total, "page": skip // limit + 1, "per_page": limit},
    }


@router.post("/batches", response_model=dict, status_code=status.HTTP_201_CREATED)
async def create_batch(
    spbu_id: int,
    data: PenyetoranBatchCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    """
    Create a batch from selected DRAFT penyetoran IDs.
    Marks included penyetoran as SUBMITTED.
    Requires: penyetoran:create permission.
    """
    try:
        batch = await penyetoran_service.create_batch(db, spbu_id, current_user.id, data)
    except (ValueError, PermissionError) as e:
        raise _service_error(e)
    return {"data": batch.model_dump(), "message": "Batch berhasil dibuat"}


@router.get("/batches/{batch_id}", response_model=dict)
async def get_batch_detail(
    spbu_id: int,
    batch_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    """
    Return detail for a single batch.
    Requires: penyetoran:view permission.
    """
    try:
        batch = await penyetoran_service.get_batch_detail(db, spbu_id, batch_id)
    except (ValueError, PermissionError) as e:
        raise _service_error(e)
    return {"data": batch.model_dump()}


@router.post("/batches/{batch_id}/submit", response_model=dict)
async def submit_batch(
    spbu_id: int,
    batch_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    """
    Submit a DRAFT batch to Manager for approval.
    Requires: penyetoran:create permission.
    """
    try:
        batch = await penyetoran_service.submit_batch(db, spbu_id, batch_id, current_user.id)
    except (ValueError, PermissionError) as e:
        raise _service_error(e)
    return {"data": batch.model_dump(), "message": "Batch berhasil di-submit"}


@router.post("/batches/{batch_id}/review", response_model=dict)
async def review_batch(
    spbu_id: int,
    batch_id: int,
    data: BatchReviewRequest,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    """
    Manager approves a submitted batch (and all its penyetoran).
    Requires: penyetoran:approve permission.
    """
    try:
        batch = await penyetoran_service.review_batch(db, spbu_id, batch_id, current_user.id, data)
    except (ValueError, PermissionError) as e:
        raise _service_error(e)
    return {"data": batch.model_dump(), "message": "Batch berhasil disetujui"}


@router.get("/batches/{batch_id}/bast-pdf")
async def download_bast_batch(
    spbu_id: int,
    batch_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    """Download BAST PDF for an approved penyetoran batch. Requires: penyetoran:view permission."""
    from fastapi.responses import Response as FastAPIResponse
    from app.utils.bast_pdf import generate_bast

    try:
        batch = await penyetoran_service.get_batch_detail(db, spbu_id, batch_id)
    except (ValueError, PermissionError) as e:
        raise _service_error(e)
    if batch.status != "approved":
        raise HTTPException(400, detail="BAST hanya tersedia untuk batch yang sudah Approved")
    from app.models.spbu import Spbu
    from sqlalchemy import select as sa_select
    spbu = (await db.execute(sa_select(Spbu).where(Spbu.id == spbu_id))).scalar_one_or_none()
    spbu_name = spbu.name if spbu else f"SPBU {spbu_id}"
    details = [
        ("Periode", f"{batch.tanggal_from} s/d {batch.tanggal_to}"),
        ("Jumlah Shift", str(len(batch.items))),
        ("Total Amount", f"Rp {batch.total_amount:,.0f}"),
    ]
    pdf_bytes = generate_bast(
        modul="Penyetoran", record_id=batch_id,
        spbu_name=spbu_name, tanggal=str(batch.tanggal_to),
        submitter_name=batch.submitted_by_name or "-",
        submitter_at=batch.submitted_at,
        approver_name=batch.reviewed_by_name or "-",
        approver_at=batch.reviewed_at,
        details=details,
    )
    filename = f"BAST-Penyetoran-{spbu_id}-{batch.tanggal_from}-{batch.tanggal_to}.pdf"
    return FastAPIResponse(content=pdf_bytes, media_type="application/pdf",
                    headers={"Content-Disposition": f'attachment; filename="{filename}"'})


@router.get("/summary/{tanggal}", response_model=dict)
async def get_daily_summary(
    spbu_id: int,
    tanggal: date,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    """
    Return the daily sales + expenses summary for a given date.
    Used to pre-populate the penyetoran view with suggested amounts.
    Requires: penyetoran:view permission.

    IMPORTANT: Declared before /{penyetoran_id} to avoid FastAPI path conflict.
    """
    try:
        summary = await penyetoran_service.get_daily_summary(db, spbu_id, tanggal)
    except (ValueError, PermissionError) as e:
        raise _service_error(e)
    return {"data": summary.model_dump()}


@router.get("/{penyetoran_id}", response_model=dict)
async def get_penyetoran_detail(
    spbu_id: int,
    penyetoran_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    """
    Return detail for a single penyetoran record.
    Requires: penyetoran:view permission.
    """
    try:
        p = await penyetoran_service.get_penyetoran_detail(db, spbu_id, penyetoran_id)
    except (ValueError, PermissionError) as e:
        raise _service_error(e)
    return {"data": p.model_dump()}


@router.patch("/{penyetoran_id}", response_model=dict)
async def update_penyetoran(
    spbu_id: int,
    penyetoran_id: int,
    data: PenyetoranUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    """
    Update catatan on a DRAFT penyetoran.
    Requires: penyetoran:edit permission.
    """
    try:
        p = await penyetoran_service.update_penyetoran(db, spbu_id, penyetoran_id, data)
    except (ValueError, PermissionError) as e:
        raise _service_error(e)
    return {"data": p.model_dump(), "message": "Penyetoran berhasil diupdate"}


@router.post("/{penyetoran_id}/bukti", response_model=dict)
async def upload_bukti(
    spbu_id: int,
    penyetoran_id: int,
    file: UploadFile = File(...),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
) -> dict:
    """
    Upload proof-of-transfer image or PDF for a penyetoran.
    Replaces any previously uploaded file.
    Supported: PDF, JPG, JPEG, PNG. Max size: 10 MB.
    Requires: penyetoran:create permission.
    """
    file_bytes = await file.read()
    filename = file.filename or "bukti"
    try:
        p = await penyetoran_service.upload_bukti(
            db, spbu_id, penyetoran_id, file_bytes, filename
        )
    except (ValueError, PermissionError) as e:
        raise _service_error(e)
    return {"data": p.model_dump(), "message": "Bukti berhasil diupload"}
