from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from app.database import get_db
from app.models.leave_request import LeaveRequest
from app.models.user import User
from app.schemas.leave_request import LeaveRequestCreate, LeaveRequestReview, LeaveRequestOut
from app.deps import get_current_user
from app.services.notifier import notify_admins, notify_user_by_id, notify_admin_group

router = APIRouter(prefix="/leave-requests", tags=["leave-requests"])


async def _enrich(req: LeaveRequest, db: AsyncSession) -> dict:
    user_res = await db.execute(select(User).where(User.id == req.user_id))
    user = user_res.scalar_one_or_none()

    reviewer = None
    if req.reviewed_by:
        rev_res = await db.execute(select(User).where(User.id == req.reviewed_by))
        reviewer = rev_res.scalar_one_or_none()

    return {
        **req.__dict__,
        "username": user.username if user else "",
        "reviewed_by_username": reviewer.username if reviewer else None,
    }


@router.get("", response_model=list[LeaveRequestOut])
async def list_leave_requests(
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    if current_user.role == "admin":
        result = await db.execute(select(LeaveRequest).order_by(LeaveRequest.created_at.desc()))
    else:
        result = await db.execute(
            select(LeaveRequest)
            .where(LeaveRequest.user_id == current_user.id)
            .order_by(LeaveRequest.created_at.desc())
        )
    rows = result.scalars().all()
    return [await _enrich(r, db) for r in rows]


@router.post("", response_model=LeaveRequestOut)
async def create_leave_request(
    payload: LeaveRequestCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    if payload.end_date < payload.start_date:
        raise HTTPException(422, "End date must be after start date")

    target_user = current_user
    if current_user.role == "admin" and payload.user_id:
        target_res = await db.execute(select(User).where(User.id == payload.user_id))
        target_user = target_res.scalar_one_or_none()
        if not target_user:
            raise HTTPException(404, "User not found")

    req = LeaveRequest(
        user_id=target_user.id,
        start_date=payload.start_date,
        end_date=payload.end_date,
        reason=payload.reason,
        status="pending",
    )
    db.add(req)
    await db.commit()
    await db.refresh(req)

    days = (payload.end_date - payload.start_date).days + 1
    body_text = f"{days} hari ({payload.start_date} – {payload.end_date}): {payload.reason or '-'}"
    await notify_admins(db, f"Pengajuan cuti: {target_user.username}", body_text, "/leave-requests")
    await notify_admin_group(db, f"Pengajuan cuti: {target_user.username}", body_text, "/leave-requests")
    await db.commit()
    return await _enrich(req, db)


@router.patch("/{req_id}/approve", response_model=LeaveRequestOut)
async def approve_leave_request(
    req_id: int,
    body: LeaveRequestReview = LeaveRequestReview(),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    if current_user.role != "admin":
        raise HTTPException(403, "Admin only")
    result = await db.execute(select(LeaveRequest).where(LeaveRequest.id == req_id))
    req = result.scalar_one_or_none()
    if not req:
        raise HTTPException(404, "Not found")
    req.status = "approved"
    req.admin_notes = body.admin_notes
    req.reviewed_by = current_user.id
    req.reviewed_at = datetime.utcnow()
    await db.commit()
    await db.refresh(req)

    # In-app only — no Telegram group (privasi)
    await notify_user_by_id(db, req.user_id, "Cuti disetujui", f"Cuti {req.start_date} – {req.end_date} telah disetujui.{(' Catatan: ' + body.admin_notes) if body.admin_notes else ''}", "/leave-requests")
    await db.commit()
    return await _enrich(req, db)


@router.patch("/{req_id}/reject", response_model=LeaveRequestOut)
async def reject_leave_request(
    req_id: int,
    body: LeaveRequestReview = LeaveRequestReview(),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    if current_user.role != "admin":
        raise HTTPException(403, "Admin only")
    result = await db.execute(select(LeaveRequest).where(LeaveRequest.id == req_id))
    req = result.scalar_one_or_none()
    if not req:
        raise HTTPException(404, "Not found")
    req.status = "rejected"
    req.admin_notes = body.admin_notes
    req.reviewed_by = current_user.id
    req.reviewed_at = datetime.utcnow()
    await db.commit()
    await db.refresh(req)

    # In-app only — no Telegram group (privasi)
    await notify_user_by_id(db, req.user_id, "Cuti ditolak", f"Cuti {req.start_date} – {req.end_date} ditolak.{(' Alasan: ' + body.admin_notes) if body.admin_notes else ''}", "/leave-requests")
    await db.commit()
    return await _enrich(req, db)


@router.delete("/{req_id}", status_code=204)
async def delete_leave_request(
    req_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    result = await db.execute(select(LeaveRequest).where(LeaveRequest.id == req_id))
    req = result.scalar_one_or_none()
    if not req:
        raise HTTPException(404, "Not found")
    if current_user.role != "admin" and req.user_id != current_user.id:
        raise HTTPException(403, "Forbidden")
    if current_user.role != "admin" and req.status != "pending":
        raise HTTPException(422, "Can only cancel pending requests")
    await db.delete(req)
    await db.commit()
