# apps/aroflo_connector_app/zones/invoices/post_processed.py
from __future__ import annotations

from typing import Any, Dict, List
from urllib.parse import urlencode
from xml.sax.saxutils import escape

from ..base import ZoneOperation, ParamSpec


def _build_postxml(invoiceids: List[str], status: str = "processed") -> str:
    # Nota: AroFlo usa <![CDATA[ ... ]]> en status
    items = []
    for inv in invoiceids:
        inv_esc = escape(inv)
        items.append(
            f"<invoice><invoiceid>{inv_esc}</invoiceid>"
            f"<status><![CDATA[ {status} ]]></status></invoice>"
        )
    return "<invoices>" + "".join(items) + "</invoices>"


def get_operations() -> List[ZoneOperation]:
    return [
        ZoneOperation(
            code="update_invoices_processed",
            label="Update Processed Invoices",
            description=(
                "Cambia el status de una o varias invoices a 'processed'. "
                "AroFlo además marca flags (linkprocessed) y puede archivar el task ligado."
            ),
            http_method="POST",
            side_effect="write",
            idempotent=False,
            default_params={"status": "processed", "raw": False},
            params=[
                ParamSpec(
                    "invoiceids",
                    "string",
                    True,
                    "Lista separada por coma de invoiceid(s) a procesar. Ej: id1,id2,id3",
                ),
                ParamSpec(
                    "status",
                    "string",
                    False,
                    "Status destino. Por defecto: processed (según doc).",
                    enum=["processed"],
                ),
                ParamSpec("raw", "boolean", False, "Si es true, devuelve respuesta cruda + meta debug."),
            ],
            category="invoices",
            use_cases=["Marcar invoices como procesadas luego de enviarlas a un sistema externo"],
            risk_level="high",
            requires_confirmation=True,
        )
    ]


def supports(operation_code: str) -> bool:
    return any(op.code == operation_code for op in get_operations())


def execute(operation_code: str, client: Any, params: Dict[str, Any]) -> Any:
    if operation_code != "update_invoices_processed":
        raise ValueError(f"[Invoices.post_processed] Operación no soportada: {operation_code}")

    raw = bool(params.get("raw", False))
    status = params.get("status", "processed")

    invoiceids_raw = params.get("invoiceids")
    if not invoiceids_raw:
        raise ValueError("invoiceids es requerido (ej: id1,id2)")

    invoiceids = [x.strip() for x in str(invoiceids_raw).split(",") if x.strip()]
    if not invoiceids:
        raise ValueError("invoiceids no contiene valores válidos")

    postxml = _build_postxml(invoiceids, status=status)

    form_params_list = [
        ("zone", "invoices"),
        ("postxml", postxml),
    ]

    var_string = urlencode(form_params_list)
    resp = client.request(
        "",
        method="POST",
        params=form_params_list,      # lista para preservar estructura
        var_string=var_string,
        data=dict(form_params_list),  # form-url-encoded (por compatibilidad)
    )

    if raw:
        return {"data": resp, "meta": {"params": form_params_list, "var_string": var_string}}

    return resp
