"""
create_agent.py — Crea los workflows del agente Sam (Kings & Queens) en n8n.

Uso:
  cd /home/edd/Proyectos/Edd-OS/projects/kings-and-queens/whatsapp-agent/workflows
  N8N_API_KEY="eyJ..." python3 create_agent.py

Qué crea:
  0. agent-error-notifier        — alerta operativa a Edd si falla un workflow
  1. kq-tool-qualify-student     — scoring de prospectos
  2. kq-tool-escalate-to-ale     — alerta a Ale vía WhatsApp (Evolution API)
  3. kq-chatwoot-agent            — agente principal Sam (GPT-4o-mini + audio/imagen)

Después de ejecutar:
  - n8n UI → asignar credencial OpenAI al nodo "GPT-4o-mini" (y "GPT-4o" si aplica)
  - Activar los 3 workflows principales
  - Chatwoot account 4 → Settings → Integrations → Webhooks
    → URL: https://n8n.edd-os.com.ar/webhook/kq-chatwoot  (event: message_created)
"""

import json
import urllib.request
import urllib.error
import sys
import os

N8N_API_KEY = os.environ.get("N8N_API_KEY", "TU_N8N_API_KEY_AQUI")
N8N_BASE    = os.environ.get("N8N_BASE_URL", "http://localhost:5678") + "/api/v1"

CHATWOOT_URL        = "http://chatwoot-web:3000"
CHATWOOT_ACCOUNT_ID = "4"
CHATWOOT_API_TOKEN  = "vqkZ6e57n5BcN1QDBQkSqsFq"
EVOLUTION_API_URL   = "https://wa.bah-ia.com.ar"
EVOLUTION_API_KEY   = "edd_secret_token"
EVOLUTION_INSTANCE  = "Kings-and-Queens"
NUMERO_ALE          = "5492914227793"
ADMIN_ALERT_WHATSAPP = os.environ.get("ADMIN_ALERT_WHATSAPP", "5492915708124")
ADMIN_ALERT_EVOLUTION_INSTANCE = os.environ.get("ADMIN_ALERT_EVOLUTION_INSTANCE", "Bah-IA")


# ─── helpers ────────────────────────────────────────────────────────────────
def api_post(path, data):
    body = json.dumps(data).encode()
    req  = urllib.request.Request(
        N8N_BASE + path, data=body,
        headers={"X-N8N-API-KEY": N8N_API_KEY, "Content-Type": "application/json"}
    )
    try:
        with urllib.request.urlopen(req) as r:
            return json.loads(r.read())
    except urllib.error.HTTPError as e:
        print(f"  ERROR {e.code}: {e.read().decode()}", file=sys.stderr)
        raise

def api_get(path):
    req = urllib.request.Request(N8N_BASE + path, headers={"X-N8N-API-KEY": N8N_API_KEY})
    with urllib.request.urlopen(req) as r:
        return json.loads(r.read())

def api_delete(path):
    req = urllib.request.Request(N8N_BASE + path, method="DELETE", headers={"X-N8N-API-KEY": N8N_API_KEY})
    try:
        with urllib.request.urlopen(req) as r:
            return r.status
    except urllib.error.HTTPError:
        pass

def delete_by_name(name):
    try:
        data = api_get("/workflows?limit=250")
        for wf in data.get("data", []):
            if wf["name"] == name:
                api_delete(f"/workflows/{wf['id']}")
                print(f"  Borrado previo: {name} (ID: {wf['id']})")
    except Exception:
        pass

def create(wf):
    delete_by_name(wf["name"])
    r = api_post("/workflows", wf)
    print(f"  Creado: {r['name']} - ID: {r['id']}")
    return r["id"]

def workflow_settings(error_workflow_id=None):
    settings = {"executionOrder": "v1"}
    if error_workflow_id:
        settings["errorWorkflow"] = error_workflow_id
    return settings

def load_js(filename):
    script_dir = os.path.dirname(os.path.abspath(__file__))
    filepath   = os.path.join(script_dir, "code-nodes", filename)
    with open(filepath, "r", encoding="utf-8") as f:
        return f.read()


# ─── system prompt ──────────────────────────────────────────────────────────
SYSTEM_PROMPT = (
    "Sos Sam, el asistente virtual de Kings & Queens English Learning, "
    "un instituto de inglés en Bahía Blanca, Argentina, dirigido por Alejandra Albornoz.\n\n"

    "## Tu identidad\n"
    "- Respondé en el idioma que use la persona (español o inglés).\n"
    "- Tono cálido, alentador y profesional. Mensajes cortos — una idea por turno.\n"
    "- Si preguntan si sos IA: 'Soy Sam, el asistente virtual de Kings & Queens.'\n\n"

    "## Tu objetivo\n"
    "Entender qué busca la persona, calificar si es buen prospecto y conectarla con Ale cuando esté lista.\n\n"

    "## Recolectá en orden natural\n"
    "1. ¿Para qué quiere aprender inglés? (trabajo, viajes, examen, gusto personal)\n"
    "2. ¿Cuál es su nivel actual?\n"
    "3. ¿Cuántas horas por semana puede dedicarle?\n"
    "4. ¿Tiene alguna fecha límite? (examen, viaje, entrevista)\n"
    "5. ¿Prefiere presencial, online o le da lo mismo?\n"
    "Cuando tengas los primeros 3 puntos, llamá a qualify_student.\n\n"

    "## Servicios\n"
    "- Clases para todos los niveles (principiante a avanzado)\n"
    "- Preparación Cambridge (B2/C1), IELTS, TOEFL\n"
    "- Inglés para trabajo y negocios\n"
    "- Individual o grupos reducidos (máx. 6)\n"
    "- Presencial Bahía Blanca o virtual (Zoom/Meet)\n\n"

    "## Precios\n"
    "Nunca des precios exactos. Siempre: 'Los valores dependen del nivel y la modalidad. "
    "Lo mejor es que hables con Ale para armar el plan que más te convenga. "
    "¿Te parece si la conecto con vos?'\n\n"

    "## Herramientas\n"
    "- qualify_student: nivel_actual, objetivo, disponibilidad_semanal_hs, urgencia_semanas, nombre_contacto\n"
    "- escalate_to_ale: cuando qualify retorna hot, o el prospecto quiere empezar ya o pide hablar con alguien.\n"
    "  Al escalar: '¡Perfecto! Le aviso a Ale ahora. ¿Preferís que te mande un WhatsApp o que te llame?'\n\n"

    "## Reglas\n"
    "- No des el número personal de Ale.\n"
    "- No prometás horarios ni cupos sin confirmar con Ale.\n"
    "- Si hay audio, procesá la transcripción como texto normal.\n"
    "- Si hay imagen, describí lo que ves y usá esa info para entender el nivel del prospecto.\n"
    "- Regla dura de errores internos: nunca menciones al cliente errores técnicos, n8n, workflows, "
    "webhooks, APIs, tokens, credenciales, stack traces, nombres de nodos, herramientas internas "
    "ni fallas de automatización.\n"
    "- Si una herramienta falla o no podés completar una acción interna, no expliques la falla. "
    "Respondé de forma humana y breve: 'Dame un segundito, voy a derivarlo internamente "
    "para que lo revisen y te respondamos bien.' Después escalá internamente si está disponible.\n"
    "- Nunca pidas al cliente que reintente por un error del sistema. El problema se resuelve internamente.\n"
)


# ─── JS: procesar mensaje con adjuntos ──────────────────────────────────────
PROCESAR_MENSAJE_JS = (
    "const body        = $json.body || $json;\n"
    "const event       = body.event;\n"
    "const messageType = body.message_type;\n"
    "const isIncoming  = messageType === 'incoming' || messageType === 0;\n"
    "\n"
    "if (event !== 'message_created' || !isIncoming) {\n"
    "  return [{ json: { skip: true, reason: `ignored: event=${event} type=${messageType}` } }];\n"
    "}\n"
    "\n"
    "const attachments   = body.attachments || [];\n"
    "const firstAttach   = attachments[0] || {};\n"
    "const attachType    = firstAttach.file_type || null;   // 'audio', 'image', etc.\n"
    "const attachUrl     = firstAttach.data_url  || null;\n"
    "\n"
    "return [{ json: {\n"
    "  skip:            false,\n"
    "  conversation_id: body.conversation?.id,\n"
    "  contact_name:    body.sender?.name || 'Prospecto',\n"
    "  content:         body.content || '',\n"
    "  contact_phone:   body.sender?.phone_number || '',\n"
    "  attach_type:     attachType,\n"
    "  attach_url:      attachUrl\n"
    "} }];\n"
)

# ─── JS: procesar adjunto (audio → Whisper / imagen → prompt visual) ────────
PROCESAR_ADJUNTO_JS = (
    "const msg = $input.first().json;\n"
    "const tipo = msg.attach_type;\n"
    "const url  = msg.attach_url;\n"
    "\n"
    "// Sin adjunto: pasar content tal cual\n"
    "if (!tipo || !url) {\n"
    "  return [{ json: { ...msg, final_content: msg.content || '', use_vision: false } }];\n"
    "}\n"
    "\n"
    "if (tipo === 'image') {\n"
    "  return [{ json: {\n"
    "    ...msg,\n"
    "    final_content: msg.content || 'El usuario envió una imagen.',\n"
    "    use_vision: true,\n"
    "    image_url: url\n"
    "  } }];\n"
    "}\n"
    "\n"
    "// Para audio: la transcripción se hace en el nodo HTTP siguiente.\n"
    "// Este nodo solo marca que hay audio para procesar.\n"
    "return [{ json: { ...msg, final_content: msg.content || '', use_vision: false, needs_transcription: true } }];\n"
)

# ─── JS: sanitizar respuesta antes de enviarla al cliente ─────────────────────
SANITIZAR_RESPUESTA_JS = (
    "const data = $input.first().json;\n"
    "const raw = String(data.output || '').trim();\n"
    "const fallback = 'Dame un segundito, voy a derivarlo internamente para que lo revisen y te respondamos bien.';\n"
    "const technicalPatterns = [\n"
    "  /\\b(n8n|workflow|webhook|api key|token|credencial|credential|stack trace|traceback)\\b/i,\n"
    "  /\\b(internal error|technical error|error interno|workflow error|node error|api error)\\b/i,\n"
    "  /\\b(http\\s*[45][0-9]{2}|cannot read properties|undefined|null|econn|etimedout|enotfound)\\b/i,\n"
    "  /\\b(Chatwoot|Evolution API|OpenAI|Whisper|Execute Workflow|tool call|toolWorkflow)\\b/i\n"
    "];\n"
    "const blocked = !raw || technicalPatterns.some((pattern) => pattern.test(raw));\n"
    "\n"
    "return [{ json: {\n"
    "  ...data,\n"
    "  output: blocked ? fallback : raw,\n"
    "  internal_error_masked: blocked,\n"
    "  original_output: blocked ? raw.slice(0, 1500) : undefined\n"
    "} }];\n"
)

# ─── JS: construir alerta para administrador desde Error Trigger ──────────────
BUILD_ERROR_ALERT_JS = (
    "const payload = $input.first().json || {};\n"
    "const execution = payload.execution || {};\n"
    "const workflow = payload.workflow || {};\n"
    "const error = execution.error || {};\n"
    "const clean = (value, max = 1200) => String(value ?? 'No informado')\n"
    "  .replace(/[\\u0000-\\u001f\\u007f]/g, ' ')\n"
    "  .replace(/\\s+/g, ' ')\n"
    "  .trim()\n"
    "  .slice(0, max);\n"
    "const when = new Date().toLocaleString('es-AR', { timeZone: 'America/Argentina/Buenos_Aires' });\n"
    "\n"
    "const message =\n"
    "  `ALERTA: Falla en agente n8n\\n\\n` +\n"
    "  `Proyecto: Kings & Queens\\n` +\n"
    "  `Workflow: ${clean(workflow.name || workflow.id)}\\n` +\n"
    "  `Nodo: ${clean(execution.lastNodeExecuted)}\\n` +\n"
    "  `Modo: ${clean(execution.mode)}\\n` +\n"
    "  `Hora: ${when}\\n\\n` +\n"
    "  `Error: ${clean(error.message)}\\n` +\n"
    "  (execution.url ? `\\nEjecucion: ${execution.url}` : '');\n"
    "\n"
    "return [{ json: { message } }];\n"
)

# ─── nodo HTTP: Whisper transcription ────────────────────────────────────────
WHISPER_NODE = {
    "id": "w1",
    "name": "Whisper Transcripcion",
    "type": "n8n-nodes-base.httpRequest",
    "typeVersion": 4.4,
    "position": [900, 500],
    "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/audio/transcriptions",
        "sendHeaders": True,
        "headerParameters": {"parameters": [
            {"name": "Authorization", "value": "Bearer {{ $credentials.openAiApi.apiKey }}"}
        ]},
        "sendBody": True,
        "contentType": "multipart-form-data",
        "bodyParameters": {"parameters": [
            {"name": "model",            "value": "whisper-1"},
            {"name": "file",             "value": "={{ $('Procesar adjunto').first().json.attach_url }}"},
            {"name": "response_format",  "value": "text"}
        ]},
        "options": {}
    }
}

# ─── nodo Enviar a Chatwoot ───────────────────────────────────────────────────
ENVIAR_CHATWOOT_NODE = {
    "id": "s9",
    "name": "Enviar a Chatwoot",
    "type": "n8n-nodes-base.httpRequest",
    "typeVersion": 4.4,
    "position": [1780, 300],
    "parameters": {
        "method": "POST",
        "url": f"=http://chatwoot-web:3000/api/v1/accounts/{CHATWOOT_ACCOUNT_ID}/conversations/{{{{ $('Procesar mensaje').first().json.conversation_id }}}}/messages",
        "sendHeaders": True,
        "headerParameters": {"parameters": [
            {"name": "api_access_token", "value": CHATWOOT_API_TOKEN}
        ]},
        "sendBody": True,
        "bodyParameters": {"parameters": [
            {"name": "content",      "value": "={{ $json.output }}"},
            {"name": "message_type", "value": "outgoing"},
            {"name": "private",      "value": "false"}
        ]},
        "options": {}
    }
}


# ─── 0. agent-error-notifier ─────────────────────────────────────────────────
print("\n[0/4] Creando agent-error-notifier...")
id_error = create({
    "name": "agent-error-notifier",
    "nodes": [
        {"id": "e1", "name": "Error Trigger",
         "type": "n8n-nodes-base.errorTrigger",
         "typeVersion": 1, "position": [240, 300], "parameters": {}},

        {"id": "e2", "name": "Build Admin Alert",
         "type": "n8n-nodes-base.code",
         "typeVersion": 2, "position": [460, 300],
         "parameters": {"jsCode": BUILD_ERROR_ALERT_JS}},

        {"id": "e3", "name": "Enviar WhatsApp a Edd",
         "type": "n8n-nodes-base.httpRequest",
         "typeVersion": 4.4, "position": [680, 300],
         "parameters": {
             "method": "POST",
             "url": f"{EVOLUTION_API_URL}/message/sendText/{ADMIN_ALERT_EVOLUTION_INSTANCE}",
             "sendHeaders": True,
             "headerParameters": {"parameters": [{"name": "apikey", "value": EVOLUTION_API_KEY}]},
             "sendBody": True,
             "specifyBody": "json",
             "jsonBody": f'={{{{ "number": "{ADMIN_ALERT_WHATSAPP}", "text": $json.message }}}}'
         }}
    ],
    "connections": {
        "Error Trigger":      {"main": [[{"node": "Build Admin Alert",    "type": "main", "index": 0}]]},
        "Build Admin Alert":  {"main": [[{"node": "Enviar WhatsApp a Edd", "type": "main", "index": 0}]]}
    },
    "settings": workflow_settings()
})


# ─── 1. kq-tool-qualify-student ──────────────────────────────────────────────
print("\n[1/4] Creando kq-tool-qualify-student...")
id_qualify = create({
    "name": "kq-tool-qualify-student",
    "nodes": [
        {"id": "n1", "name": "When Called by Tool",
         "type": "n8n-nodes-base.executeWorkflowTrigger",
         "typeVersion": 1, "position": [240, 300], "parameters": {}},
        {"id": "n2", "name": "Qualify Student",
         "type": "n8n-nodes-base.code",
         "typeVersion": 2, "position": [460, 300],
         "parameters": {"jsCode": load_js("tool-qualify-student.js")}}
    ],
    "connections": {
        "When Called by Tool": {"main": [[{"node": "Qualify Student", "type": "main", "index": 0}]]}
    },
    "settings": workflow_settings(id_error)
})


# ─── 2. kq-tool-escalate-to-ale ──────────────────────────────────────────────
print("\n[2/4] Creando kq-tool-escalate-to-ale...")
id_escalate = create({
    "name": "kq-tool-escalate-to-ale",
    "nodes": [
        {"id": "n1", "name": "When Called by Tool",
         "type": "n8n-nodes-base.executeWorkflowTrigger",
         "typeVersion": 1, "position": [240, 300], "parameters": {}},

        {"id": "n2", "name": "Build Message",
         "type": "n8n-nodes-base.code",
         "typeVersion": 2, "position": [460, 300],
         "parameters": {"jsCode": load_js("tool-escalate-to-ale.js")}},

        # Envía WhatsApp a Ale vía Evolution API (producción real)
        {"id": "n3", "name": "Enviar WhatsApp a Ale",
         "type": "n8n-nodes-base.httpRequest",
         "typeVersion": 4.4, "position": [680, 300],
         "parameters": {
             "method": "POST",
             "url": f"{EVOLUTION_API_URL}/message/sendText/{EVOLUTION_INSTANCE}",
             "sendHeaders": True,
             "headerParameters": {"parameters": [{"name": "apikey", "value": EVOLUTION_API_KEY}]},
             "sendBody": True,
             "specifyBody": "json",
             "jsonBody": f'={{{{ "number": "{NUMERO_ALE}", "text": $json.message }}}}'
         }}
    ],
    "connections": {
        "When Called by Tool": {"main": [[{"node": "Build Message",         "type": "main", "index": 0}]]},
        "Build Message":       {"main": [[{"node": "Enviar WhatsApp a Ale", "type": "main", "index": 0}]]}
    },
    "settings": workflow_settings(id_error)
})


# ─── 3. kq-chatwoot-agent ────────────────────────────────────────────────────
print("\n[3/4] Creando kq-chatwoot-agent...")

id_agent = create({
    "name": "kq-chatwoot-agent",
    "nodes": [

        # 1. Webhook
        {"id": "s1", "name": "Chatwoot Webhook",
         "type": "n8n-nodes-base.webhook",
         "typeVersion": 1, "position": [240, 300],
         "parameters": {
             "httpMethod": "POST",
             "path": "kq-chatwoot",
             "responseMode": "lastNode",
             "options": {}
         }},

        # 2. Extraer campos + filtrar
        {"id": "s2", "name": "Procesar mensaje",
         "type": "n8n-nodes-base.code",
         "typeVersion": 2, "position": [460, 300],
         "parameters": {"jsCode": PROCESAR_MENSAJE_JS}},

        # 3. IF: mensaje válido
        {"id": "s3", "name": "Mensaje valido?",
         "type": "n8n-nodes-base.if",
         "typeVersion": 1, "position": [680, 300],
         "parameters": {
             "conditions": {"boolean": [{"value1": "={{ $json.skip }}", "value2": False}]}
         }},

        # 4. Procesar adjunto (audio/imagen)
        {"id": "s4", "name": "Procesar adjunto",
         "type": "n8n-nodes-base.code",
         "typeVersion": 2, "position": [900, 200],
         "parameters": {"jsCode": PROCESAR_ADJUNTO_JS}},

        # 5. IF: necesita transcripción de audio
        {"id": "s5", "name": "Es audio?",
         "type": "n8n-nodes-base.if",
         "typeVersion": 1, "position": [1100, 200],
         "parameters": {
             "conditions": {"boolean": [{"value1": "={{ $json.needs_transcription === true }}", "value2": True}]}
         }},

        # 6. Whisper: transcribir audio
        WHISPER_NODE,

        # 7. AI Agent: Sam (texto/audio)
        {"id": "s7", "name": "Sam - AI Agent",
         "type": "@n8n/n8n-nodes-langchain.agent",
         "typeVersion": 1, "position": [1340, 300],
         "parameters": {
             "promptType": "define",
             "text": "={{ $('Procesar mensaje').first().json.contact_name + ': ' + ($json.needs_transcription ? $('Whisper Transcripcion').first().json.text : $('Procesar adjunto').first().json.final_content) }}",
             "options": {"systemMessage": SYSTEM_PROMPT}
         }},

        # 8. Sanitizar respuesta para no exponer fallas internas al cliente
        {"id": "s12", "name": "Sanitizar respuesta",
         "type": "n8n-nodes-base.code",
         "typeVersion": 2, "position": [1560, 300],
         "parameters": {"jsCode": SANITIZAR_RESPUESTA_JS}},

        # 9. GPT-4o (sub-nodo LLM)
        {"id": "s8", "name": "GPT-4o",
         "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
         "typeVersion": 1, "position": [1180, 480],
         "parameters": {"model": "gpt-4o", "options": {}}},

        # 10. Window Buffer Memory
        {"id": "s9m", "name": "Window Buffer Memory",
         "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
         "typeVersion": 1, "position": [1340, 480],
         "parameters": {
             "sessionKey": "={{ String($('Procesar mensaje').first().json.conversation_id) }}",
             "contextWindowLength": 20
         }},

        # 11. Tool: qualify_student
        {"id": "s10", "name": "qualify_student",
         "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
         "typeVersion": 1.2, "position": [1500, 480],
         "parameters": {
             "name": "qualify_student",
             "description": (
                 "Califica un prospecto de Kings & Queens con score 0-10. "
                 "Llamar cuando tengas: nivel actual, objetivo y disponibilidad. "
                 "Campos: nivel_actual, objetivo, disponibilidad_semanal_hs, urgencia_semanas, nombre_contacto"
             ),
             "workflowId": {"__rl": True, "value": id_qualify, "mode": "id"},
             "fields": {"values": []}
         }},

        # 12. Tool: escalate_to_ale
        {"id": "s11", "name": "escalate_to_ale",
         "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
         "typeVersion": 1.2, "position": [1660, 480],
         "parameters": {
             "name": "escalate_to_ale",
             "description": (
                 "Avisa a Ale (directora de Kings & Queens) sobre un prospecto caliente por WhatsApp. "
                 "Llamar cuando qualify_student retorna clasificacion=hot, o el prospecto quiere empezar ya. "
                 "Campos: nombre, nivel, score (del qualify), resumen (2-3 lineas)"
             ),
             "workflowId": {"__rl": True, "value": id_escalate, "mode": "id"},
             "fields": {"values": []}
         }},

        # 13. Enviar respuesta a Chatwoot
        ENVIAR_CHATWOOT_NODE,

        # 14. Respond 200: skip
        {"id": "s13", "name": "Respond 200 Skip",
         "type": "n8n-nodes-base.respondToWebhook",
         "typeVersion": 1, "position": [900, 400],
         "parameters": {"respondWith": "text", "responseBody": "OK"}},

        # 15. Respond 200: fin flujo
        {"id": "s14", "name": "Respond 200",
         "type": "n8n-nodes-base.respondToWebhook",
         "typeVersion": 1, "position": [2000, 300],
         "parameters": {"respondWith": "text", "responseBody": "OK"}}
    ],

    "connections": {
        "Chatwoot Webhook":    {"main": [[{"node": "Procesar mensaje",  "type": "main", "index": 0}]]},
        "Procesar mensaje":    {"main": [[{"node": "Mensaje valido?",   "type": "main", "index": 0}]]},
        "Mensaje valido?":     {"main": [
            [{"node": "Procesar adjunto",  "type": "main", "index": 0}],
            [{"node": "Respond 200 Skip",  "type": "main", "index": 0}]
        ]},
        "Procesar adjunto":    {"main": [[{"node": "Es audio?",         "type": "main", "index": 0}]]},
        "Es audio?":           {"main": [
            [{"node": "Whisper Transcripcion", "type": "main", "index": 0}],
            [{"node": "Sam - AI Agent",        "type": "main", "index": 0}]
        ]},
        "Whisper Transcripcion": {"main": [[{"node": "Sam - AI Agent",  "type": "main", "index": 0}]]},
        "Sam - AI Agent":      {"main": [[{"node": "Sanitizar respuesta", "type": "main", "index": 0}]]},
        "Sanitizar respuesta": {"main": [[{"node": "Enviar a Chatwoot",   "type": "main", "index": 0}]]},
        "Enviar a Chatwoot":   {"main": [[{"node": "Respond 200",         "type": "main", "index": 0}]]},

        "GPT-4o":              {"ai_languageModel": [[{"node": "Sam - AI Agent", "type": "ai_languageModel", "index": 0}]]},
        "Window Buffer Memory": {"ai_memory":        [[{"node": "Sam - AI Agent", "type": "ai_memory",        "index": 0}]]},
        "qualify_student":      {"ai_tool":          [[{"node": "Sam - AI Agent", "type": "ai_tool",          "index": 0}]]},
        "escalate_to_ale":      {"ai_tool":          [[{"node": "Sam - AI Agent", "type": "ai_tool",          "index": 1}]]}
    },

    "settings": workflow_settings(id_error)
})


# ─── resumen ─────────────────────────────────────────────────────────────────
print("\n" + "="*60)
print("WORKFLOWS CREADOS")
print("="*60)
print(f"\n  agent-error-notifier     → ID: {id_error}")
print(f"  kq-tool-qualify-student  → ID: {id_qualify}")
print(f"  kq-tool-escalate-to-ale  → ID: {id_escalate}")
print(f"  kq-chatwoot-agent        → ID: {id_agent}")
print(f"""
PROXIMOS PASOS:
1. n8n UI → asignar credencial OpenAI al nodo "GPT-4o-mini"
2. Activar los 3 workflows principales (toggle)
3. Chatwoot account 4 → Settings → Integrations → Webhooks
   URL: https://n8n.edd-os.com.ar/webhook/kq-chatwoot
   Event: message_created
4. Opcional: setear ADMIN_ALERT_WHATSAPP para cambiar el celular de alertas.
   Opcional: setear ADMIN_ALERT_EVOLUTION_INSTANCE para cambiar la instancia de envío.
   Fallback actual: {ADMIN_ALERT_WHATSAPP}
   Instancia de alertas: {ADMIN_ALERT_EVOLUTION_INSTANCE}
""")
