"""Router for PB (Permintaan Barang) endpoints."""

from fastapi import APIRouter, BackgroundTasks, Depends, File, HTTPException, Query, 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.pb import (
    PBCreate, PBUpdate, PBHeadReviewBody,
    ProjectCreate, ProjectUpdate,
)
from app.services import pb_service, telegram_service

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


def _err(e: Exception) -> HTTPException:
    if isinstance(e, PermissionError):
        return HTTPException(status_code=403, detail=str(e))
    return HTTPException(status_code=400, detail=str(e))


# ── Projects ──────────────────────────────────────────────────────────────────

@router.get("/projects", response_model=dict)
async def list_projects(
    spbu_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    rows = await pb_service.list_projects(db, spbu_id)
    return {"data": [r.model_dump() for r in rows]}


@router.post("/projects", response_model=dict, status_code=201)
async def create_project(
    spbu_id: int,
    body: ProjectCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    try:
        proj = await pb_service.create_project(db, spbu_id, body)
    except Exception as e:
        raise _err(e)
    return {"data": proj.model_dump(), "message": "Project berhasil dibuat"}


@router.patch("/projects/{project_id}", response_model=dict)
async def update_project(
    spbu_id: int,
    project_id: int,
    body: ProjectUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    try:
        proj = await pb_service.update_project(db, spbu_id, project_id, body)
    except Exception as e:
        raise _err(e)
    return {"data": proj.model_dump(), "message": "Project berhasil diupdate"}


# ── PB ────────────────────────────────────────────────────────────────────────

@router.get("", response_model=dict)
async def list_pbs(
    spbu_id: int,
    status: str | None = Query(default=None),
    project_id: int | None = Query(default=None),
    skip: int = Query(default=0, ge=0),
    limit: int = Query(default=50, ge=1, le=100),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    rows, total = await pb_service.list_pbs(db, spbu_id, status, project_id, skip, limit)
    return {
        "data": [r.model_dump() for r in rows],
        "meta": {"total": total, "skip": skip, "limit": limit},
    }


@router.post("", response_model=dict, status_code=201)
async def create_pb(
    spbu_id: int,
    body: PBCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    try:
        pb = await pb_service.create_pb(db, spbu_id, current_user.id, body)
    except Exception as e:
        raise _err(e)
    return {"data": pb.model_dump(), "message": "PB berhasil disimpan"}


@router.get("/{pb_id}", response_model=dict)
async def get_pb(
    spbu_id: int,
    pb_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    try:
        pb = await pb_service.get_pb(db, spbu_id, pb_id)
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))
    return {"data": pb.model_dump()}


@router.patch("/{pb_id}", response_model=dict)
async def update_pb(
    spbu_id: int,
    pb_id: int,
    body: PBUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    try:
        pb = await pb_service.update_pb(db, spbu_id, pb_id, body)
    except Exception as e:
        raise _err(e)
    return {"data": pb.model_dump(), "message": "PB berhasil diupdate"}


@router.delete("/{pb_id}", response_model=dict)
async def delete_pb(
    spbu_id: int,
    pb_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    try:
        await pb_service.delete_pb(db, spbu_id, pb_id)
    except Exception as e:
        raise _err(e)
    return {"message": "PB berhasil dihapus"}


@router.post("/{pb_id}/submit", response_model=dict)
async def submit_pb(
    spbu_id: int, pb_id: int,
    background_tasks: BackgroundTasks,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    try:
        pb = await pb_service.submit_pb(db, spbu_id, pb_id, current_user.id)
    except Exception as e:
        raise _err(e)
    background_tasks.add_task(telegram_service.notify_pb_submitted, spbu_id, pb_id)
    return {"data": pb.model_dump(), "message": "PB berhasil di-submit"}


@router.post("/{pb_id}/recall", response_model=dict)
async def recall_pb(
    spbu_id: int, pb_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    try:
        pb = await pb_service.recall_pb(db, spbu_id, pb_id, current_user.id)
    except Exception as e:
        raise _err(e)
    return {"data": pb.model_dump(), "message": "PB berhasil di-recall"}


@router.post("/{pb_id}/forward", response_model=dict)
async def forward_pb(
    spbu_id: int, pb_id: int,
    body: PBUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    try:
        pb = await pb_service.forward_pb(db, spbu_id, pb_id, current_user, body)
    except Exception as e:
        raise _err(e)
    return {"data": pb.model_dump(), "message": "PB berhasil dikirim untuk approval"}


@router.post("/{pb_id}/pull-back", response_model=dict)
async def pull_back_pb(
    spbu_id: int, pb_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    try:
        pb = await pb_service.pull_back_pb(db, spbu_id, pb_id, current_user)
    except Exception as e:
        raise _err(e)
    return {"data": pb.model_dump(), "message": "PB berhasil di-pull back"}


@router.post("/{pb_id}/review", response_model=dict)
async def review_pb(
    spbu_id: int, pb_id: int,
    body: PBHeadReviewBody,
    background_tasks: BackgroundTasks,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    try:
        pb = await pb_service.review_pb(db, spbu_id, pb_id, current_user, body)
    except Exception as e:
        raise _err(e)
    background_tasks.add_task(telegram_service.notify_pb_reviewed, spbu_id, pb_id)
    status_label = "diapprove" if any(i["status"] == "approved" for i in body.items) else "ditolak"
    return {"data": pb.model_dump(), "message": f"PB berhasil {status_label}"}


@router.post("/{pb_id}/attachment", response_model=dict, status_code=201)
async def upload_attachment(
    spbu_id: int,
    pb_id: int,
    file: UploadFile = File(...),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    file_bytes = await file.read()
    if len(file_bytes) > 10 * 1024 * 1024:
        raise HTTPException(status_code=400, detail="File terlalu besar (max 10 MB)")
    try:
        pb = await pb_service.upload_attachment(db, spbu_id, pb_id, file_bytes, file.filename or "attachment")
    except Exception as e:
        raise _err(e)
    return {"data": pb.model_dump(), "message": "Attachment berhasil diupload"}


@router.get("/{pb_id}/ledger", response_model=dict)
async def get_pb_ledger(
    spbu_id: int,
    pb_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    try:
        ledger = await pb_service.get_pb_ledger(db, spbu_id, pb_id)
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))
    return {"data": ledger.model_dump()}


@router.get("/{pb_id}/activity-log", response_model=dict)
async def get_activity_log(
    spbu_id: int,
    pb_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_spbu_access),
):
    from sqlalchemy import select as sa_select
    from app.models.audit import AuditLog
    from sqlalchemy.orm import selectinload
    result = await db.execute(
        sa_select(AuditLog)
        .options(selectinload(AuditLog.user))
        .where(AuditLog.modul == "pb", AuditLog.object_id == pb_id, AuditLog.spbu_id == spbu_id)
        .order_by(AuditLog.created_at.asc())
    )
    rows = result.scalars().all()
    return {"data": [{"aksi": r.aksi, "user_name": r.user.name if r.user else None,
                      "created_at": r.created_at.isoformat() if r.created_at else None,
                      "detail": r.detail} for r in rows]}
