from celery import Task

from core.celery_app import celery_app
from core.database import scoped_core_db
from core.exceptions import ErrorCollector, ValidationException

from api.v1.modules.a76.invoices.models import InvoiceHeader
from .pre_validators import pre_validators
from .main_process import revert_process


def _progress(task: Task, current: int, status: str) -> None:
    task.update_state(state="PROGRESS", meta={"current": current, "status": status})


@celery_app.task(bind=True, name="revert_export_invoice_task")
def revert_invoice_task(
    self: Task,
    invoice_id: int,
    tenant_id: str,
    company_id: str,
    cancelled_by: str | None = None,
) -> dict:
    """
    Des-actualiza una factura de importación temporal ejecutando todas las
    validaciones y reversiones del proceso principal (revert/main_process) con
    reporte de progreso.
    """
    with scoped_core_db(tenant_id=int(tenant_id), company_id=int(company_id)) as db:
        try:
            _progress(self, 5, "Cargando factura...")
            invoice: InvoiceHeader | None = db.get(InvoiceHeader, invoice_id)
            if invoice is None:
                return {
                    "status": "error",
                    "message": f"Factura con id {invoice_id} no encontrada.",
                    "errors": [],
                }

            _progress(self, 10, "Verificando estatus de seguridad...")
            from api.v1.modules.a76.invoices.models import InvoiceStatus
            if invoice.status != InvoiceStatus.PROCESSED:
                return {
                    "status": "error",
                    "message": f"La factura {invoice.invoice_number} no se puede revertir porque no está procesada.",
                    "errors": [{"field": "status", "message": "Factura no procesada."}],
                }

            errors = ErrorCollector()

            _progress(self, 10, "Validando estatus de la factura...")
            lines = pre_validators(db, invoice, tenant_id, company_id, errors)
            if not lines:
                errors.add_error(
                    field="line_items",
                    message="La factura no contiene partidas para revertir",
                    solution=["Verifique que la factura tenga partidas antes de intentar revertirla"],
                    code="NO_LINE_ITEMS",
                )
            errors.raise_if_errors()

            _progress(self, 40, "Verificando saldos de partidas...")
            sql_errors = revert_process(
                db=db,
                invoice=invoice,
                lines=lines,
                tenant_id=tenant_id,
                company_id=company_id,
                errors=errors,
                cancelled_by=cancelled_by,
            )

            _progress(self, 95, "Anulando saldos de inventario y confirmando...")
            db.flush()
            db.commit()

            return {
                "status": "success",
                "invoice_id": invoice_id,
                "sql_errors": sql_errors,
            }

        except ValidationException as exc:
            db.rollback()
            return {
                "status": "validation_error",
                "message": exc.message,
                "errors": exc.errors,
            }
        except Exception as exc:
            db.rollback()
            raise exc
