from __future__ import annotations

from decimal import Decimal
from typing import Any

from fastapi import APIRouter, Depends, HTTPException

from app.modules.auth.presentation.auth import get_current_user, require_role
from app.core.postgres.project_crud_repository import ProjectCrudRepository
from app.modules.operations.application.ai_site_diary_service import AISiteDiaryService

from .models import IpcCreateRequest, VoiceSiteDiaryRequest

router = APIRouter()


@router.post("/projects/{project_id}/voice-site-diary")
def create_voice_site_diary(
    project_id: str,
    payload: VoiceSiteDiaryRequest,
    current_user: dict[str, Any] = Depends(
        require_role(["superadmin", "director", "pm", "site_engineer"])
    ),
) -> dict[str, Any]:
    """Xử lý bóc tách nhật ký thi công từ giọng nói / văn bản của Kỹ sư công trường."""
    service = AISiteDiaryService()
    return service.process_voice_to_diary(
        project_id=project_id,
        transcript_text=payload.transcript_text,
        weather_override=payload.weather_override,
        temp_override=payload.temperature_override,
    )


@router.post("/projects/{project_id_or_code}/generate-ipc-dossier")
def generate_fidic_ipc_dossier(
    project_id_or_code: str,
    current_user: dict[str, Any] = Depends(
        require_role(["superadmin", "director", "pm", "site_engineer", "qs", "accountant"])
    ),
) -> dict[str, Any]:
    """Tự động gom và lắp ráp bộ hồ sơ thanh toán IPC chuẩn FIDIC."""
    service = AISiteDiaryService()
    return service.assemble_fidic_ipc_dossier(project_id_or_code)


@router.get("/projects/{project_id}/ipcs")
def list_project_ipcs(
    project_id: str,
    current_user: dict[str, Any] = Depends(
        require_role(["superadmin", "director", "pm", "site_engineer", "qs", "accountant"])
    ),
) -> list[dict[str, Any]]:
    """Lấy danh sách các đợt tạm ứng, nghiệm thu thanh toán giai đoạn IPC và tiền giữ lại."""
    repo = ProjectCrudRepository()
    detail = repo.get_project_detail(project_id)
    if not detail:
        raise HTTPException(status_code=404, detail="Không tìm thấy dự án")

    p_id = detail["id"]
    rows = repo.list_project_ipcs(str(p_id))

    formatted = []
    for r in rows:
        formatted.append(
            {
                "id": str(r["id"]),
                "project_id": str(r["project_id"]),
                "ipc_number": r["ipc_number"],
                "billing_period_start": str(r["billing_period_start"])
                if r["billing_period_start"]
                else None,
                "billing_period_end": str(r["billing_period_end"])
                if r["billing_period_end"]
                else None,
                "gross_claimed_amount_vnd": float(r["gross_claimed_amount_vnd"]),
                "advance_recovery_amount_vnd": float(r["advance_recovery_amount_vnd"]),
                "retention_withheld_amount_vnd": float(
                    r["retention_withheld_amount_vnd"]
                ),
                "net_certified_amount_vnd": float(r["net_certified_amount_vnd"]),
                "status": r["status"],
                "invoice_ref": f"{r['invoice_series'] or ''}-{r['invoice_number'] or ''}"
                if r["matched_invoice_id"]
                else None,
            }
        )
    return formatted


@router.post("/projects/{project_id}/ipcs", status_code=201)
def create_project_ipc(
    project_id: str,
    payload: IpcCreateRequest,
    current_user: dict[str, Any] = Depends(
        require_role(["superadmin", "director", "pm", "site_engineer", "qs", "accountant"])
    ),
) -> dict[str, Any]:
    """Tạo đợt IPC thanh toán mới kèm hạch toán giữ lại tiền bảo hành."""
    repo = ProjectCrudRepository()
    detail = repo.get_project_detail(project_id)
    if not detail:
        raise HTTPException(status_code=404, detail="Không tìm thấy dự án")

    p_id = detail["id"]
    gross = Decimal(str(payload.gross_claimed_amount_vnd))
    advance = Decimal(str(payload.advance_recovery_amount_vnd))
    retention = Decimal(str(payload.retention_withheld_amount_vnd))
    net = Decimal(str(payload.net_certified_amount_vnd))

    if advance <= 0:
        advance_percent = Decimal(
            str(detail.get("advance_payment_percent") or 10.0)
        ) / Decimal(100)
        advance = gross * advance_percent

    if retention <= 0:
        retention_percent = Decimal(
            str(detail.get("retention_percent") or 5.0)
        ) / Decimal(100)
        retention = gross * retention_percent

    if net <= 0:
        net = gross - advance - retention

    try:
        ipc_id = repo.create_project_ipc(
            project_id=str(p_id),
            ipc_number=payload.ipc_number,
            billing_period_start=payload.billing_period_start,
            billing_period_end=payload.billing_period_end,
            gross_claimed_amount_vnd=gross,
            advance_recovery_amount_vnd=advance,
            retention_withheld_amount_vnd=retention,
            net_certified_amount_vnd=net,
            status=payload.status,
            matched_invoice_id=payload.matched_invoice_id,
        )
        return {
            "status": "success",
            "ipc_id": ipc_id,
            "message": f"Tạo đợt IPC số {payload.ipc_number} thành công.",
        }
    except Exception as e:
        raise HTTPException(status_code=400, detail=f"Không thể tạo đợt IPC: {e!s}")
