#!/usr/bin/env python3
"""
n8n API client for Tony (OpenClaw workspace)
Instance: https://primary-production-62cf.up.railway.app (Railway self-hosted)
Auth: X-N8N-API-KEY header (JWT)
"""

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

# --- Config ---
def get_config():
    """Load API key from .env file or environment."""
    api_key = os.environ.get("N8N_API_KEY")
    base_url = os.environ.get("N8N_URL", "https://primary-production-62cf.up.railway.app")

    if not api_key:
        env_path = os.path.expanduser("~/.openclaw/workspace/.env")
        if os.path.exists(env_path):
            with open(env_path) as f:
                for line in f:
                    line = line.strip()
                    if line.startswith("N8N_API_KEY="):
                        api_key = line.split("=", 1)[1]
                    elif line.startswith("N8N_URL="):
                        base_url = line.split("=", 1)[1]

    if not api_key:
        print("❌ N8N_API_KEY not found in environment or ~/.openclaw/workspace/.env")
        sys.exit(1)

    return api_key.strip(), base_url.strip().rstrip("/")


def api_request(path, method="GET", data=None):
    """Make an authenticated request to the n8n API."""
    api_key, base_url = get_config()
    url = f"{base_url}/api/v1{path}"
    headers = {
        "X-N8N-API-KEY": api_key,
        "Content-Type": "application/json",
        "Accept": "application/json",
    }

    body = json.dumps(data).encode() if data else None
    req = urllib.request.Request(url, data=body, headers=headers, method=method)

    try:
        with urllib.request.urlopen(req, timeout=15) as resp:
            return json.loads(resp.read())
    except urllib.error.HTTPError as e:
        body = e.read().decode()
        print(f"❌ HTTP {e.code}: {body}")
        sys.exit(1)
    except urllib.error.URLError as e:
        print(f"❌ Connection failed: {e.reason}")
        sys.exit(1)


# --- Commands ---

def cmd_status():
    """Check instance health."""
    _, base_url = get_config()
    url = f"{base_url}/healthz"
    try:
        req = urllib.request.Request(url, headers={"Accept": "application/json"})
        with urllib.request.urlopen(req, timeout=10) as resp:
            data = json.loads(resp.read())
            print(f"✅ n8n instance is UP")
            print(f"   URL: {base_url}")
            print(f"   Status: {data.get('status', 'ok')}")
    except Exception as e:
        print(f"❌ Instance unreachable: {e}")
        sys.exit(1)

    # Also get version info if available
    try:
        info = api_request("/")
        if isinstance(info, dict):
            print(f"   Version: {info.get('version', 'unknown')}")
    except:
        pass


def cmd_workflows(filter_active=None):
    """List all workflows."""
    data = api_request("/workflows?limit=100")
    workflows = data.get("data", [])

    if filter_active == "active":
        workflows = [w for w in workflows if w.get("active")]
    elif filter_active == "inactive":
        workflows = [w for w in workflows if not w.get("active")]

    active_count = sum(1 for w in workflows if w.get("active"))
    total = len(workflows)

    print(f"📋 n8n Workflows ({total} total, {active_count} active)")
    print(f"   Instance: https://primary-production-62cf.up.railway.app")
    print()

    for wf in workflows:
        status = "✅" if wf.get("active") else "⏸"
        wf_id = wf.get("id", "?")
        name = wf.get("name", "Unnamed")
        tags = ", ".join(t.get("name", "") for t in wf.get("tags", []))
        tag_str = f" [{tags}]" if tags else ""
        print(f"  {status} {name}{tag_str}")
        print(f"     ID: {wf_id}")


def cmd_workflow_detail(workflow_id):
    """Get details of a specific workflow."""
    data = api_request(f"/workflows/{workflow_id}")
    name = data.get("name", "Unknown")
    active = data.get("active", False)
    nodes = data.get("nodes", [])
    tags = [t.get("name", "") for t in data.get("tags", [])]

    print(f"📄 Workflow: {name}")
    print(f"   ID: {workflow_id}")
    print(f"   Status: {'✅ Active' if active else '⏸ Inactive'}")
    print(f"   Nodes: {len(nodes)}")
    if tags:
        print(f"   Tags: {', '.join(tags)}")
    print()
    print("   Node types used:")
    node_types = sorted(set(n.get("type", "?").split(".")[-1] for n in nodes))
    for nt in node_types:
        print(f"     • {nt}")


def cmd_executions(workflow_id=None, limit=10):
    """List recent executions."""
    path = f"/executions?limit={limit}"
    if workflow_id:
        path += f"&workflowId={workflow_id}"

    data = api_request(path)
    executions = data.get("data", [])

    wf_label = f" for workflow {workflow_id}" if workflow_id else ""
    print(f"⚡ Recent executions{wf_label} (last {limit}):")
    print()

    if not executions:
        print("   No executions found.")
        return

    for ex in executions:
        ex_id = ex.get("id", "?")
        status = ex.get("status", "?")
        wf_id = ex.get("workflowId", "?")
        started = ex.get("startedAt", "?")
        finished = ex.get("stoppedAt", "")

        status_icon = {"success": "✅", "error": "❌", "running": "🔄", "waiting": "⏳"}.get(status, "❓")
        print(f"  {status_icon} [{status}] exec:{ex_id}")
        print(f"     Workflow: {wf_id}")
        print(f"     Started: {started}")
        if finished:
            print(f"     Finished: {finished}")
        print()


def cmd_trigger(workflow_id):
    """Trigger a workflow by ID (via webhook or activation)."""
    # n8n doesn't have a direct "trigger" API endpoint for arbitrary workflows
    # We need to use the webhook trigger or the execute endpoint
    # Try the execute endpoint first
    print(f"🚀 Triggering workflow: {workflow_id}")

    # Get workflow details to find webhook URL
    try:
        wf = api_request(f"/workflows/{workflow_id}")
        name = wf.get("name", "Unknown")
        nodes = wf.get("nodes", [])

        # Look for webhook trigger node
        webhook_nodes = [n for n in nodes if "webhook" in n.get("type", "").lower()]
        if webhook_nodes:
            wn = webhook_nodes[0]
            path_val = wn.get("parameters", {}).get("path", "")
            if path_val:
                _, base_url = get_config()
                webhook_url = f"{base_url}/webhook/{path_val}"
                print(f"   Found webhook trigger: {webhook_url}")
                print(f"   Use: curl -X POST {webhook_url}")
                return

        # Try the manual execute endpoint
        result = api_request(f"/workflows/{workflow_id}/run", method="POST", data={})
        print(f"   ✅ Triggered: {name}")
        print(f"   Execution ID: {result.get('executionId', '?')}")

    except SystemExit:
        print(f"   ⚠️  Could not trigger workflow {workflow_id}")
        print(f"   Note: Workflows can only be triggered if they have a webhook or manual trigger node.")
        print(f"   Try activating it instead: n8n.sh activate {workflow_id}")


def cmd_activate(workflow_id):
    """Activate a workflow."""
    result = api_request(f"/workflows/{workflow_id}/activate", method="POST")
    name = result.get("name", workflow_id)
    active = result.get("active", False)
    if active:
        print(f"✅ Activated: {name} ({workflow_id})")
    else:
        print(f"⚠️  Activation returned but workflow not active: {name}")


def cmd_deactivate(workflow_id):
    """Deactivate a workflow."""
    result = api_request(f"/workflows/{workflow_id}/deactivate", method="POST")
    name = result.get("name", workflow_id)
    active = result.get("active", True)
    if not active:
        print(f"⏸ Deactivated: {name} ({workflow_id})")
    else:
        print(f"⚠️  Deactivation returned but workflow still active: {name}")


def cmd_find(query):
    """Find a workflow by name (fuzzy match)."""
    data = api_request("/workflows?limit=100")
    workflows = data.get("data", [])
    query_lower = query.lower()

    matches = [w for w in workflows if query_lower in w.get("name", "").lower()]

    if not matches:
        print(f"❌ No workflows matching: '{query}'")
        return

    print(f"🔍 Workflows matching '{query}':")
    for wf in matches:
        status = "✅" if wf.get("active") else "⏸"
        print(f"  {status} {wf['name']} — ID: {wf['id']}")


def cmd_help():
    print("""n8n CLI — Tony's skill for controlling the Railway n8n instance

Usage: n8n.sh <command> [args]

Commands:
  status                  Check instance health
  workflows               List all workflows (name, id, active)
  workflows active        List only active workflows
  workflows inactive      List only inactive workflows
  find <query>            Search workflows by name
  detail <workflow_id>    Show workflow node details
  executions              List recent executions (all workflows)
  executions <id>         List recent executions for a specific workflow
  trigger <workflow_id>   Trigger a workflow (webhook or manual run)
  activate <workflow_id>  Activate a workflow
  deactivate <workflow_id> Deactivate a workflow
  help                    Show this help

Instance: https://primary-production-62cf.up.railway.app (Railway)
API Key:  ~/.openclaw/workspace/.env → N8N_API_KEY
""")


# --- Main ---
def main():
    args = sys.argv[1:]
    if not args:
        cmd_help()
        return

    cmd = args[0].lower()

    if cmd == "status":
        cmd_status()
    elif cmd == "workflows":
        filter_arg = args[1] if len(args) > 1 else None
        cmd_workflows(filter_arg)
    elif cmd == "find":
        if len(args) < 2:
            print("Usage: n8n.sh find <query>")
            sys.exit(1)
        cmd_find(" ".join(args[1:]))
    elif cmd == "detail":
        if len(args) < 2:
            print("Usage: n8n.sh detail <workflow_id>")
            sys.exit(1)
        cmd_workflow_detail(args[1])
    elif cmd == "executions":
        wf_id = args[1] if len(args) > 1 else None
        cmd_executions(wf_id)
    elif cmd == "trigger":
        if len(args) < 2:
            print("Usage: n8n.sh trigger <workflow_id>")
            sys.exit(1)
        cmd_trigger(args[1])
    elif cmd == "activate":
        if len(args) < 2:
            print("Usage: n8n.sh activate <workflow_id>")
            sys.exit(1)
        cmd_activate(args[1])
    elif cmd == "deactivate":
        if len(args) < 2:
            print("Usage: n8n.sh deactivate <workflow_id>")
            sys.exit(1)
        cmd_deactivate(args[1])
    elif cmd == "help":
        cmd_help()
    else:
        print(f"❌ Unknown command: {cmd}")
        cmd_help()
        sys.exit(1)


if __name__ == "__main__":
    main()

# TONY-APPROVED: 2026-03-01 | sha:b8172bf7
