#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Cierra el Patrón B (Fuente=REDES SOCIALES) en el workflow n8n [2004]
(ddUEORBEtZLzsQF2).

Contexto: la rama "Creado por usuario" pone Canal=SUCURSAL a los WEB_USER/
MOBILE_USER. Para un contacto con Fuente=REDES SOCIALES eso es incoherente
(redes sociales = canal digital). Decisión de negocio (2026-05-30): tratarlos
como digital -> Canal=FACEBOOK + Fuente=LEAD DIGITAL (igual que hizo el fix de
datos `scripts/fix_origen_fuente_incoherencia.py` Patrón B).

Cambio (solo AÑADE / re-cablea, preserva el camino SUCURSAL existente):
  1. Extiende el Code node para exponer `fuenteEsRedesSociales`.
  2. Intercala, en la rama true del IF "Creado por usuario", un IF
     "Fuente es REDES SOCIALES":
       [true]  -> PUT Canal=FACEBOOK -> PUT Fuente=LEAD DIGITAL  (camino digital)
       [false] -> PUT Canal de Origen = SUCURSAL                  (camino existente intacto)

  Antes:  Creado por usuario --true--> [PUT Canal=SUCURSAL -> tags -> IF LEAD DIGITAL -> PUT Fuente=SUCURSAL]
  Ahora:  Creado por usuario --true--> IF REDES SOCIALES
                                          --true--> PUT Canal=FACEBOOK -> PUT Fuente=LEAD DIGITAL
                                          --false-> [PUT Canal=SUCURSAL -> ... (igual que antes)]

Solo toca custom fields del contacto (no tags ni opps), igual que el fix de datos.
[2004] dispara al CREAR contacto.

Uso:
    python n8n/_add_redes_sociales_branch.py            # dry-run (dumpea payload)
    python n8n/_add_redes_sociales_branch.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.
CODE_NODE = 'Buscar "contact.sucursal" y "contact.tienda"'
VERIFICADOR_NODE = "Buscar Sucursal en Verificador de Sucursales"
IF_USUARIO_NODE = "Creado por usuario (Canal de Origen)"
PUT_CANAL_SUCURSAL_NODE = "PUT Canal de Origen = SUCURSAL"

# Nodos nuevos.
IF_REDES_NODE = "Fuente es REDES SOCIALES"
PUT_CANAL_FB_NODE = "PUT Canal de Origen = FACEBOOK"
PUT_FUENTE_LD_NODE = "PUT Fuente de Prospecto = LEAD DIGITAL"

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: versión con fuente (de _add_fuente_reconcile.py) + flag fuenteEsRedesSociales.
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.
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 fuenteNorm = String(fuenteActual || "").trim().toUpperCase();
const fuenteEsLeadDigital = fuenteNorm === "LEAD DIGITAL";
const fuenteEsRedesSociales = fuenteNorm === "REDES SOCIALES";

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,
      fuenteEsRedesSociales: fuenteEsRedesSociales,
    },
  },
];"""


def put_cf_node(name, position, *, code_field, value):
    """Nodo httpRequest PUT /contacts/{id} que setea un custom field por id+key."""
    body = (
        "={\n"
        '  "customFields": [\n'
        "    {\n"
        '      "id": "{{ ' + CODE_REF + "." + code_field + '.id }}",\n'
        '      "key": "{{ ' + CODE_REF + "." + code_field + '.fieldKey }}",\n'
        '      "field_value": "' + value + '"\n'
        "    }\n"
        "  ]\n"
        "}"
    )
    return {
        "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": body,
            "options": {"redirect": {"redirect": {}}},
        },
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 4.2,
        "position": position,
        "name": name,
    }


def build_nodes():
    if_redes = {
        "parameters": {
            "conditions": {
                "options": {"caseSensitive": True, "leftValue": "", "typeValidation": "loose", "version": 3},
                "conditions": [
                    {
                        "id": "fuente-es-redes-sociales",
                        "leftValue": "={{ " + CODE_REF + ".fuenteEsRedesSociales }}",
                        "rightValue": "",
                        "operator": {"type": "boolean", "operation": "true", "singleValue": True},
                    }
                ],
                "combinator": "and",
            },
            "options": {},
        },
        "type": "n8n-nodes-base.if",
        "typeVersion": 2.3,
        "position": [820, -320],
        "name": IF_REDES_NODE,
    }
    put_canal_fb = put_cf_node(PUT_CANAL_FB_NODE, [1040, -320], code_field="canal", value="FACEBOOK")
    put_fuente_ld = put_cf_node(PUT_FUENTE_LD_NODE, [1260, -320], code_field="fuente", value="LEAD DIGITAL")
    return if_redes, put_canal_fb, put_fuente_ld


def main():
    parser = argparse.ArgumentParser(description="Cierra Patrón B (REDES SOCIALES) 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="redes_sociales")
    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_REDES_NODE, PUT_CANAL_FB_NODE, PUT_FUENTE_LD_NODE):
        if client.find_node(wf, nm) is not None:
            raise SystemExit(f"El nodo {nm!r} ya existe; ya fue aplicado. Nada que hacer.")

    # Pre-requisitos.
    for nm in (IF_USUARIO_NODE, PUT_CANAL_SUCURSAL_NODE):
        if client.find_node(wf, nm) is None:
            raise SystemExit(f"No existe {nm!r}; corre antes _add_canal_origen_branch.py.")

    # Verifica que el IF "Creado por usuario" hoy conecta su rama true a PUT Canal=SUCURSAL.
    cur = client.get_connection_targets(wf, IF_USUARIO_NODE, output_index=0)
    cur_names = [t.get("node") for t in cur]
    if cur_names != [PUT_CANAL_SUCURSAL_NODE]:
        raise SystemExit(f"Topología inesperada: {IF_USUARIO_NODE!r} true -> {cur_names} (esperaba [{PUT_CANAL_SUCURSAL_NODE!r}]).")

    # 1. Extender Code node.
    code_node = client.find_node(wf, CODE_NODE)
    code_node["parameters"]["jsCode"] = NEW_JSCODE
    print(f"  Code node {CODE_NODE!r}: jsCode extendido (fuenteEsRedesSociales).")

    # 2. Añadir nodos.
    if_redes, put_canal_fb, put_fuente_ld = build_nodes()
    for n in (if_redes, put_canal_fb, put_fuente_ld):
        client.assert_idempotent(wf, n["name"])
        client.add_node(wf, n)
    print("  Nodos añadidos: IF REDES + PUT Canal=FACEBOOK + PUT Fuente=LEAD DIGITAL.")

    # 3. Re-cablear: Creado por usuario[true] -> IF REDES;
    #    IF REDES[true] -> PUT Canal=FACEBOOK -> PUT Fuente=LEAD DIGITAL;
    #    IF REDES[false] -> PUT Canal=SUCURSAL (camino existente).
    client.set_connection(wf, IF_USUARIO_NODE, IF_REDES_NODE, output_index=0)
    client.set_connection(wf, IF_REDES_NODE, PUT_CANAL_FB_NODE, output_index=0)
    client.set_connection(wf, IF_REDES_NODE, PUT_CANAL_SUCURSAL_NODE, output_index=1)
    client.set_connection(wf, PUT_CANAL_FB_NODE, PUT_FUENTE_LD_NODE)
    print("  Conexiones re-cableadas.")

    expected = [IF_REDES_NODE, PUT_CANAL_FB_NODE, PUT_FUENTE_LD_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: Patrón B cerrado y verificado. Backup en:", backup_path)


if __name__ == "__main__":
    main()
