#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Endurece el workflow n8n [2004] (ddUEORBEtZLzsQF2) para CERRAR LA CAUSA RAÍZ
del Patrón A (Canal=SUCURSAL & Fuente=LEAD DIGITAL).

Contexto: la rama "Creado por usuario" (añadida por `_add_canal_origen_branch.py`)
pone Canal de Origen=SUCURSAL a los contactos WEB_USER/MOBILE_USER pero NO toca
Fuente de Prospecto, dejando huérfano un `LEAD DIGITAL` previo -> incoherencia.

Este complemento (solo AÑADE, preserva el flujo) reconcilia la Fuente SOLO cuando
vale exactamente "LEAD DIGITAL" (preserva ALIANZA / PROSPECCIÓN / CLIENTE CONOCIDO
/ etc., que con Canal=SUCURSAL son válidas):

  1. Extiende el Code node para resolver el field "Fuente de Prospecto"
     (fieldKey `contact.fuente_de_prospecto`, fallback por nombre) y leer su VALOR
     ACTUAL del GET individual del contacto -> expone `fuente`, `fuenteActual`,
     `fuenteEsLeadDigital`.
  2. Tras `Tag- facebook-ads` añade:
       IF "Fuente = LEAD DIGITAL (reconciliar)" -> [true] PUT Fuente=SUCURSAL
       [false] (fin: no se toca).

Solo corre dentro de la rama esUsuario=true (ya gateada aguas arriba por el IF
"Creado por usuario"). El [2004] dispara al CREAR contacto, así que no revierte
ediciones manuales posteriores.

Uso:
    python n8n/_add_fuente_reconcile.py            # dry-run (dumpea payload)
    python n8n/_add_fuente_reconcile.py --apply     # aplica + reactiva
"""

import argparse
import os
import sys

ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if ROOT_DIR not in sys.path:
    sys.path.insert(0, ROOT_DIR)

from scripts.n8n_workflow_lib import N8NClient, load_credentials  # noqa: E402

WID = "ddUEORBEtZLzsQF2"

# Nodos existentes (referencias).
CODE_NODE = 'Buscar "contact.sucursal" y "contact.tienda"'
GET_CONTACT_NODE = "Obtener Contacto Cuenta Origen - SUCURSAL"
VERIFICADOR_NODE = "Buscar Sucursal en Verificador de Sucursales"
TAG_RM_FB_NODE = "Tag- facebook-ads"  # último nodo de la rama canal de origen

# Nodos nuevos.
IF_FUENTE_NODE = "Fuente = LEAD DIGITAL (reconciliar)"
PUT_FUENTE_NODE = "PUT Fuente de Prospecto = SUCURSAL"

CONTACT_ID_EXPR = "{{ $('Datos de Lead').item.json.Cliente['Contact ID'] }}"
TOKEN_EXPR = "{{ $('" + VERIFICADOR_NODE + "').item.json['SC TOKEN BUCEFALO'] }}"
CODE_REF = "$('" + CODE_NODE + "').item.json"

HEADERS = [
    {"name": "Accept", "value": "application/json"},
    {"name": "Version", "value": "2021-07-28"},
    {"name": "Authorization", "value": "=Bearer " + TOKEN_EXPR},
]

# Code node extendido: preserva VERBATIM la lógica sucursal/tienda/canal/esUsuario
# y AÑADE la resolución de Fuente + su valor actual + flag fuenteEsLeadDigital.
NEW_JSCODE = r"""const customFields = $input.first().json.customFields;

function findField(key, names) {
  let f = customFields.find(x => x.fieldKey === key);
  if (!f) {
    const wanted = names.map(n => n.toLowerCase().trim());
    f = customFields.find(x => wanted.includes((x.name || "").toLowerCase().trim()));
  }
  return f || null;
}

const sucursalField = findField("contact.sucursal", ["Sucursal"]);
const tiendaField = findField("contact.tienda", ["TIENDA", "Tienda"]);
const canalField = findField("contact.fuente_de_posible_cliente", ["CANAL DE ORIGEN", "Canal de Origen"]);
const fuenteField = findField("contact.fuente_de_prospecto", ["Fuente de Prospecto", "FUENTE DE PROSPECTO"]);

// createdBy.source SOLO viene del GET individual del contacto.
const contactResp = $('Obtener Contacto Cuenta Origen - SUCURSAL').item.json;
const createdBySource =
  (contactResp && contactResp.contact && contactResp.contact.createdBy && contactResp.contact.createdBy.source) ||
  (contactResp && contactResp.createdBy && contactResp.createdBy.source) ||
  null;
const esUsuario = createdBySource === "WEB_USER" || createdBySource === "MOBILE_USER";

// Valor ACTUAL de "Fuente de Prospecto" en el contacto (para reconciliar SOLO si = LEAD DIGITAL).
const contactCFs =
  (contactResp && contactResp.contact && contactResp.contact.customFields) ||
  (contactResp && contactResp.customFields) ||
  [];
let fuenteActual = null;
if (fuenteField && fuenteField.id) {
  const hit = contactCFs.find(cf => cf.id === fuenteField.id);
  fuenteActual = hit ? (hit.value != null ? hit.value : (hit.fieldValue != null ? hit.fieldValue : null)) : null;
}
const fuenteEsLeadDigital = String(fuenteActual || "").trim().toUpperCase() === "LEAD DIGITAL";

return [
  {
    json: {
      sucursal: {
        id: sucursalField?.id ?? null,
        name: sucursalField?.name ?? null,
        fieldKey: sucursalField?.fieldKey ?? null,
        picklistOptions: sucursalField?.picklistOptions ?? [],
      },
      tienda: {
        id: tiendaField?.id ?? null,
        name: tiendaField?.name ?? null,
        fieldKey: tiendaField?.fieldKey ?? null,
        picklistOptions: tiendaField?.picklistOptions ?? [],
      },
      canal: {
        id: canalField?.id ?? null,
        name: canalField?.name ?? null,
        fieldKey: canalField?.fieldKey ?? null,
        picklistOptions: canalField?.picklistOptions ?? [],
      },
      fuente: {
        id: fuenteField?.id ?? null,
        name: fuenteField?.name ?? null,
        fieldKey: fuenteField?.fieldKey ?? null,
        picklistOptions: fuenteField?.picklistOptions ?? [],
      },
      createdBySource: createdBySource,
      esUsuario: esUsuario,
      fuenteActual: fuenteActual,
      fuenteEsLeadDigital: fuenteEsLeadDigital,
    },
  },
];"""


def build_nodes():
    if_node = {
        "parameters": {
            "conditions": {
                "options": {"caseSensitive": True, "leftValue": "", "typeValidation": "loose", "version": 3},
                "conditions": [
                    {
                        "id": "fuente-es-lead-digital",
                        "leftValue": "={{ " + CODE_REF + ".fuenteEsLeadDigital }}",
                        "rightValue": "",
                        "operator": {"type": "boolean", "operation": "true", "singleValue": True},
                    }
                ],
                "combinator": "and",
            },
            "options": {},
        },
        "type": "n8n-nodes-base.if",
        "typeVersion": 2.3,
        "position": [1820, -120],
        "name": IF_FUENTE_NODE,
    }

    fuente_body = (
        "={\n"
        '  "customFields": [\n'
        "    {\n"
        '      "id": "{{ ' + CODE_REF + '.fuente.id }}",\n'
        '      "key": "{{ ' + CODE_REF + '.fuente.fieldKey }}",\n'
        '      "field_value": "SUCURSAL"\n'
        "    }\n"
        "  ]\n"
        "}"
    )
    put_fuente = {
        "parameters": {
            "method": "PUT",
            "url": "=https://services.leadconnectorhq.com/contacts/" + CONTACT_ID_EXPR,
            "sendHeaders": True,
            "headerParameters": {"parameters": [dict(h) for h in HEADERS]},
            "sendBody": True,
            "specifyBody": "json",
            "jsonBody": fuente_body,
            "options": {"redirect": {"redirect": {}}},
        },
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 4.2,
        "position": [2040, -120],
        "name": PUT_FUENTE_NODE,
    }
    return if_node, put_fuente


def main():
    parser = argparse.ArgumentParser(description="Reconcilia Fuente=LEAD DIGITAL->SUCURSAL en [2004].")
    parser.add_argument("--apply", action="store_true", help="Aplica el PUT real (sin esto: dry-run).")
    args = parser.parse_args()

    client = N8NClient(*load_credentials())
    wf, backup_path = client.backup_workflow(WID, label="fuente_reconcile")
    prev_version = wf.get("versionId")
    print(f"Workflow: {wf.get('name')}")
    print(f"  active={wf.get('active')} nodes={len(wf.get('nodes') or [])} versionId={prev_version}")
    print(f"  backup -> {backup_path}")

    # Idempotencia.
    for nm in (IF_FUENTE_NODE, PUT_FUENTE_NODE):
        if client.find_node(wf, nm) is not None:
            raise SystemExit(f"El nodo {nm!r} ya existe; el complemento ya fue aplicado. Nada que hacer.")

    # Pre-requisito: la rama canal de origen debe existir (TAG_RM_FB_NODE es su cola).
    if client.find_node(wf, TAG_RM_FB_NODE) is None:
        raise SystemExit(f"No existe {TAG_RM_FB_NODE!r}; corre antes _add_canal_origen_branch.py.")

    # 1. Extender el Code node (preserva lógica previa, añade fuente).
    code_node = client.find_node(wf, CODE_NODE)
    if code_node is None:
        raise SystemExit(f"No se encontró el Code node {CODE_NODE!r}.")
    code_node["parameters"]["jsCode"] = NEW_JSCODE
    print(f"  Code node {CODE_NODE!r}: jsCode extendido (fuente + fuenteEsLeadDigital).")

    # 2. Añadir nodos.
    if_node, put_fuente = build_nodes()
    for n in (if_node, put_fuente):
        client.assert_idempotent(wf, n["name"])
        client.add_node(wf, n)
    print("  Nodos añadidos: IF Fuente + PUT Fuente=SUCURSAL.")

    # 3. Conexiones: Tag- facebook-ads -> IF -> [true] PUT Fuente. [false] fin.
    client.set_connection(wf, TAG_RM_FB_NODE, IF_FUENTE_NODE)
    client.set_connection(wf, IF_FUENTE_NODE, PUT_FUENTE_NODE, output_index=0)
    print("  Conexiones cableadas.")

    expected = [IF_FUENTE_NODE, PUT_FUENTE_NODE]

    if not args.apply:
        res = client.put_workflow(WID, wf, dry_run=True)
        print(f"\nDRY-RUN. Payload -> {res['path']} ({res['node_count']} nodos).")
        print("Revisa el JSON y vuelve a correr con --apply para aplicar.")
        return

    was_active = bool(wf.get("active"))
    if was_active:
        try:
            client.deactivate(WID)
            print("  Workflow desactivado para PUT estructural.")
        except Exception as exc:
            print(f"  WARN al desactivar: {exc}")
    client.put_workflow(WID, wf, dry_run=False)
    print("  PUT aplicado.")
    if was_active:
        client.activate(WID)
        print("  Workflow reactivado.")
    client.verify_post(WID, expected_node_names=expected, prev_version_id=prev_version)
    print("\nOK: complemento aplicado y verificado. Backup en:", backup_path)


if __name__ == "__main__":
    main()
