from typing import Any, Dict

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session

from core.celery_app import celery_app
from core.database import get_core_db
from core.security import get_current_user, validate_access_to_resource
from api.v1.modules.core.tasks_tracking import track_and_dispatch

from api.v1.modules.a76.invoices.models import InvoiceHeader, OperationType
from api.v1.modules.a76.invoices.permission_map import get_invoice_permission_base
from .task import revert_invoice_task as revert_import_invoice_task
from ...exports.revert.task import revert_invoice_task as revert_export_invoice_task

router = APIRouter()


@router.post("/invoices/{invoice_id}/revert")
def trigger_invoice_revert(
    invoice_id: int,
    company_id: int = Query(..., description="Company ID"),
    db: Session = Depends(get_core_db),
    current_user: Dict[str, Any] = Depends(get_current_user),
):
    """
    Endpoint unificado para des-actualizar facturas.
    - operation_type=imp -> task de importación
    - operation_type=exp -> task de exportación
    """
    tenant_id = validate_access_to_resource(db, company_id, current_user)
    cancelled_by = (
        current_user.get("username")
        or current_user.get("user_name")
        or current_user.get("preferred_username")
        or current_user.get("email")
        or "system"
    )

    invoice: InvoiceHeader | None = db.get(InvoiceHeader, invoice_id)
    if invoice is None:
        raise HTTPException(status_code=404, detail=f"Factura {invoice_id} no encontrada.")

    # 🛡️ Validación de permisos granulares: des-actualizar requiere el mismo permiso que procesar
    perm_base = get_invoice_permission_base(invoice.operation_type, invoice.invoice_type)
    validate_access_to_resource(db, company_id, current_user, required_permissions=[f"{perm_base}.process"])

    if invoice.operation_type == OperationType.EXP:
        task = track_and_dispatch(
            db=db,
            task=revert_export_invoice_task,
            tenant_id=tenant_id,
            company_id=company_id,
            requested_by_user=str(cancelled_by),
            task_name="revert_export_invoice_task",
            task_group="invoices",
            task_origin="a76/invoices/exports/revert",
            args=[invoice_id, str(tenant_id), str(company_id), str(cancelled_by)],
        )
    else:
        task = track_and_dispatch(
            db=db,
            task=revert_import_invoice_task,
            tenant_id=tenant_id,
            company_id=company_id,
            requested_by_user=str(cancelled_by),
            task_name="revert_invoice_task",
            task_group="invoices",
            task_origin="a76/invoices/imports/revert",
            args=[invoice_id, str(tenant_id), str(company_id), str(cancelled_by)],
        )

    return {"task_id": task.id}


@router.get("/invoices/revert/{task_id}/status")
def get_invoice_revert_status(task_id: str):
    """
    Consulta el estado de progreso de una tarea de des-actualización de
    factura.

    Retorna:
      - state: 'PROCESSING' | 'SUCCESS' | 'FAILURE'
      - info: { current: int, status: str }  (cuando state == 'PROCESSING')
      - result: dict                          (cuando state == 'SUCCESS' o 'FAILURE')
    """
    task_result = celery_app.AsyncResult(task_id)

    if task_result.state in ("PENDING", "STARTED"):
        return {
            "state": "PROCESSING",
            "info": {"current": 0, "status": "Iniciando..."},
        }

    if task_result.state == "PROGRESS":
        return {
            "state": "PROCESSING",
            "info": task_result.info or {"current": 0, "status": "Procesando..."},
        }

    if task_result.state == "SUCCESS":
        return {
            "state": "SUCCESS",
            "result": task_result.result,
        }

    error_info = task_result.result
    if isinstance(error_info, Exception):
        error_msg = str(error_info)
    else:
        error_msg = str(error_info) if error_info else "Error desconocido"

    return {
        "state": "FAILURE",
        "result": error_msg,
    }
