import React, { useState, useCallback, useMemo } from "react";
import { createRoot } from "react-dom/client";
import { useApp, useHostStyles } from "@modelcontextprotocol/ext-apps/react";

/* ─── Types ───────────────────────────────────────────────────── */

interface WorkflowNode {
  id: string;
  name: string;
  type: string;
  typeVersion: number;
  position: [number, number];
  parameters: Record<string, unknown>;
}

interface ConnectionTarget {
  node: string;
  type: string;
  index: number;
}

interface WorkflowConnections {
  [sourceName: string]: {
    main: ConnectionTarget[][];
  };
}

interface WorkflowData {
  id: string;
  name: string;
  active: boolean;
  nodes: WorkflowNode[];
  connections: WorkflowConnections;
  settings: Record<string, unknown>;
  versionId: string;
  createdAt: string;
  updatedAt: string;
}

type TabId = "overview" | "nodes" | "connections" | "settings" | "versions";

/* ─── Helpers ─────────────────────────────────────────────────── */

function formatDate(iso: string): string {
  if (!iso) return "—";
  try {
    return new Date(iso).toLocaleString(undefined, {
      year: "numeric",
      month: "short",
      day: "numeric",
      hour: "2-digit",
      minute: "2-digit",
    });
  } catch {
    return iso;
  }
}

function shortType(type: string): string {
  return type.replace(/^n8n-nodes-base\./, "").replace(/^@[^/]+\//, "");
}

function isTriggerType(type: string): boolean {
  return /trigger/i.test(type) || /webhook/i.test(type);
}

function countConnections(conns: WorkflowConnections): number {
  let count = 0;
  for (const src of Object.values(conns)) {
    for (const group of src.main) {
      count += group.length;
    }
  }
  return count;
}

function getTriggerType(nodes: WorkflowNode[]): string {
  const trigger = nodes.find((n) => isTriggerType(n.type));
  return trigger ? shortType(trigger.type) : "Manual";
}

/* ─── Tab: Overview ───────────────────────────────────────────── */

function OverviewTab({ data }: { data: WorkflowData }) {
  const nodeCount = data.nodes.length;
  const connCount = countConnections(data.connections);
  const triggerType = getTriggerType(data.nodes);

  // Build ordered flow chain via BFS
  const orderedNodes = useMemo(() => {
    const adjacency = new Map<string, string[]>();
    const inDegree = new Map<string, number>();
    data.nodes.forEach((n) => {
      adjacency.set(n.name, []);
      inDegree.set(n.name, 0);
    });
    for (const [srcName, connDef] of Object.entries(data.connections)) {
      for (const group of connDef.main) {
        for (const target of group) {
          adjacency.get(srcName)?.push(target.node);
          inDegree.set(target.node, (inDegree.get(target.node) || 0) + 1);
        }
      }
    }
    // Topological sort (Kahn)
    const queue = data.nodes
      .filter((n) => (inDegree.get(n.name) || 0) === 0)
      .map((n) => n.name);
    const sorted: string[] = [];
    while (queue.length) {
      const current = queue.shift()!;
      sorted.push(current);
      for (const neighbor of adjacency.get(current) || []) {
        const newDeg = (inDegree.get(neighbor) || 1) - 1;
        inDegree.set(neighbor, newDeg);
        if (newDeg === 0) queue.push(neighbor);
      }
    }
    // Add any remaining nodes not in the sorted list
    for (const n of data.nodes) {
      if (!sorted.includes(n.name)) sorted.push(n.name);
    }
    return sorted;
  }, [data.nodes, data.connections]);

  const nodeMap = useMemo(() => {
    const m = new Map<string, WorkflowNode>();
    data.nodes.forEach((n) => m.set(n.name, n));
    return m;
  }, [data.nodes]);

  return (
    <div>
      {/* Stat cards */}
      <div className="stats-row">
        <div className="stat-card accent">
          <div className="stat-value">{nodeCount}</div>
          <div className="stat-label">Nodes</div>
        </div>
        <div className="stat-card">
          <div className="stat-value">{connCount}</div>
          <div className="stat-label">Connections</div>
        </div>
        <div className="stat-card">
          <div className="stat-value" style={{ fontSize: 18 }}>
            {triggerType}
          </div>
          <div className="stat-label">Trigger Type</div>
        </div>
        <div className="stat-card">
          <div className="stat-value" style={{ fontSize: 16, fontFamily: "var(--font-mono)" }}>
            {data.versionId ? data.versionId.slice(0, 8) : "—"}
          </div>
          <div className="stat-label">Version</div>
        </div>
      </div>

      {/* Flow visualization */}
      <div className="card" style={{ marginBottom: 16 }}>
        <div className="card-header">
          <span style={{ fontWeight: 600, fontSize: 13 }}>⚡ Workflow Flow</span>
          <span style={{ fontSize: 12, color: "var(--color-text-muted)" }}>
            {nodeCount} nodes
          </span>
        </div>
        <div className="card-body">
          <div className="flow-container">
            {orderedNodes.map((nodeName, i) => {
              const node = nodeMap.get(nodeName);
              if (!node) return null;
              const isTrigger = isTriggerType(node.type);
              return (
                <React.Fragment key={node.id}>
                  {i > 0 && <span className="flow-arrow">→</span>}
                  <div className={`flow-node${isTrigger ? " trigger" : ""}`}>
                    {isTrigger ? "⚡" : "⚙️"} {node.name}
                  </div>
                </React.Fragment>
              );
            })}
          </div>
        </div>
      </div>
    </div>
  );
}

/* ─── Tab: Nodes ──────────────────────────────────────────────── */

function NodesTab({ data }: { data: WorkflowData }) {
  const [expandedId, setExpandedId] = useState<string | null>(null);
  const [sortCol, setSortCol] = useState<"name" | "type" | "version">("name");
  const [sortAsc, setSortAsc] = useState(true);

  const sorted = useMemo(() => {
    const copy = [...data.nodes];
    copy.sort((a, b) => {
      let cmp = 0;
      if (sortCol === "name") cmp = a.name.localeCompare(b.name);
      else if (sortCol === "type") cmp = a.type.localeCompare(b.type);
      else cmp = a.typeVersion - b.typeVersion;
      return sortAsc ? cmp : -cmp;
    });
    return copy;
  }, [data.nodes, sortCol, sortAsc]);

  const handleSort = (col: typeof sortCol) => {
    if (sortCol === col) setSortAsc(!sortAsc);
    else {
      setSortCol(col);
      setSortAsc(true);
    }
  };

  const sortIcon = (col: string) =>
    sortCol === col ? (sortAsc ? " ↑" : " ↓") : "";

  return (
    <div className="card">
      <div className="table-wrap">
        <table>
          <thead>
            <tr>
              <th style={{ cursor: "pointer" }} onClick={() => handleSort("name")}>
                Name{sortIcon("name")}
              </th>
              <th style={{ cursor: "pointer" }} onClick={() => handleSort("type")}>
                Type{sortIcon("type")}
              </th>
              <th style={{ cursor: "pointer" }} onClick={() => handleSort("version")}>
                Version{sortIcon("version")}
              </th>
              <th>Position</th>
            </tr>
          </thead>
          <tbody>
            {sorted.map((node) => (
              <React.Fragment key={node.id}>
                <tr
                  onClick={() =>
                    setExpandedId(expandedId === node.id ? null : node.id)
                  }
                  style={{ cursor: "pointer" }}
                >
                  <td>
                    <span style={{ display: "flex", alignItems: "center", gap: 8 }}>
                      {isTriggerType(node.type) ? "⚡" : "⚙️"}
                      <strong>{node.name}</strong>
                    </span>
                  </td>
                  <td>
                    <span className="badge n8n">{shortType(node.type)}</span>
                  </td>
                  <td>{node.typeVersion}</td>
                  <td style={{ fontFamily: "var(--font-mono)", fontSize: 12 }}>
                    [{node.position[0]}, {node.position[1]}]
                  </td>
                </tr>
                {expandedId === node.id && (
                  <tr>
                    <td colSpan={4} style={{ padding: 0 }}>
                      <div
                        style={{
                          padding: "16px 20px",
                          background: "var(--color-bg)",
                          borderTop: "1px solid var(--color-border)",
                          animation: "slideUp 0.2s ease-out",
                        }}
                      >
                        <div
                          style={{
                            fontSize: 11,
                            fontWeight: 600,
                            textTransform: "uppercase",
                            letterSpacing: 0.5,
                            color: "var(--color-text-muted)",
                            marginBottom: 8,
                          }}
                        >
                          Parameters
                        </div>
                        {Object.keys(node.parameters).length > 0 ? (
                          <pre className="code">
                            {JSON.stringify(node.parameters, null, 2)}
                          </pre>
                        ) : (
                          <p style={{ color: "var(--color-text-dim)", fontSize: 13 }}>
                            No parameters configured
                          </p>
                        )}
                      </div>
                    </td>
                  </tr>
                )}
              </React.Fragment>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

/* ─── Tab: Connections ────────────────────────────────────────── */

function ConnectionsTab({ data }: { data: WorkflowData }) {
  const connList = useMemo(() => {
    const list: { source: string; target: string; outputIndex: number; inputIndex: number }[] = [];
    for (const [sourceName, connDef] of Object.entries(data.connections)) {
      connDef.main.forEach((group, outputIndex) => {
        group.forEach((target) => {
          list.push({
            source: sourceName,
            target: target.node,
            outputIndex,
            inputIndex: target.index,
          });
        });
      });
    }
    return list;
  }, [data.connections]);

  if (connList.length === 0) {
    return (
      <div className="empty-state">
        <div className="icon">🔗</div>
        <h3>No Connections</h3>
        <p>This workflow has no node connections defined.</p>
      </div>
    );
  }

  return (
    <div>
      <div className="card" style={{ marginBottom: 16 }}>
        <div className="card-header">
          <span style={{ fontWeight: 600, fontSize: 13 }}>🔗 Connection Map</span>
          <span style={{ fontSize: 12, color: "var(--color-text-muted)" }}>
            {connList.length} connection{connList.length !== 1 ? "s" : ""}
          </span>
        </div>
        <div className="card-body">
          <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
            {connList.map((conn, i) => (
              <div
                key={i}
                style={{
                  display: "flex",
                  alignItems: "center",
                  gap: 12,
                  padding: "10px 16px",
                  background: "var(--color-bg)",
                  borderRadius: "var(--radius-sm)",
                  border: "1px solid var(--color-border)",
                  transition: "border-color var(--transition)",
                }}
                className="conn-row"
              >
                <div className="flow-node" style={{ margin: 0 }}>
                  {conn.source}
                </div>
                <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 2 }}>
                  <span style={{ color: "var(--color-n8n)", fontSize: 18, lineHeight: 1 }}>→</span>
                  <span style={{ fontSize: 10, color: "var(--color-text-dim)" }}>
                    out[{conn.outputIndex}] → in[{conn.inputIndex}]
                  </span>
                </div>
                <div className="flow-node" style={{ margin: 0 }}>
                  {conn.target}
                </div>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

/* ─── Tab: Settings ───────────────────────────────────────────── */

function SettingsTab({ data }: { data: WorkflowData }) {
  const settings = data.settings || {};
  const entries = Object.entries(settings);

  if (entries.length === 0) {
    return (
      <div className="empty-state">
        <div className="icon">⚙️</div>
        <h3>Default Settings</h3>
        <p>This workflow uses all default settings — no custom configuration.</p>
      </div>
    );
  }

  return (
    <div className="card">
      <div className="card-header">
        <span style={{ fontWeight: 600, fontSize: 13 }}>⚙️ Workflow Settings</span>
      </div>
      <div className="card-body">
        <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
          {entries.map(([key, value]) => (
            <div
              key={key}
              style={{
                display: "flex",
                justifyContent: "space-between",
                alignItems: "flex-start",
                gap: 16,
                padding: "10px 0",
                borderBottom: "1px solid var(--color-border)",
              }}
            >
              <label
                style={{
                  fontSize: 13,
                  fontWeight: 600,
                  color: "var(--color-text)",
                  minWidth: 180,
                  flexShrink: 0,
                }}
              >
                {key}
              </label>
              <div
                style={{
                  fontSize: 13,
                  fontFamily: "var(--font-mono)",
                  color: "var(--color-text-muted)",
                  wordBreak: "break-all",
                  textAlign: "right",
                }}
              >
                {typeof value === "object"
                  ? JSON.stringify(value, null, 2)
                  : String(value)}
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

/* ─── Tab: Versions ───────────────────────────────────────────── */

function VersionsTab({ data }: { data: WorkflowData }) {
  return (
    <div>
      <div className="card">
        <div className="card-header">
          <span style={{ fontWeight: 600, fontSize: 13 }}>📋 Version History</span>
        </div>
        <div className="card-body">
          <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
            {/* Current version */}
            <div
              style={{
                padding: 16,
                background: "var(--color-bg)",
                borderRadius: "var(--radius-sm)",
                border: "1px solid var(--color-n8n)",
              }}
            >
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }}>
                <span style={{ fontWeight: 700, fontSize: 14 }}>Current Version</span>
                <span className="badge active">Active</span>
              </div>
              <div style={{ display: "flex", gap: 24, flexWrap: "wrap" }}>
                <div>
                  <div style={{ fontSize: 11, color: "var(--color-text-dim)", textTransform: "uppercase", letterSpacing: 0.5, marginBottom: 2 }}>
                    Version ID
                  </div>
                  <div style={{ fontFamily: "var(--font-mono)", fontSize: 13 }}>
                    {data.versionId || "—"}
                  </div>
                </div>
                <div>
                  <div style={{ fontSize: 11, color: "var(--color-text-dim)", textTransform: "uppercase", letterSpacing: 0.5, marginBottom: 2 }}>
                    Created
                  </div>
                  <div style={{ fontSize: 13 }}>{formatDate(data.createdAt)}</div>
                </div>
                <div>
                  <div style={{ fontSize: 11, color: "var(--color-text-dim)", textTransform: "uppercase", letterSpacing: 0.5, marginBottom: 2 }}>
                    Last Updated
                  </div>
                  <div style={{ fontSize: 13 }}>{formatDate(data.updatedAt)}</div>
                </div>
              </div>
            </div>

            {/* Placeholder for older versions */}
            <div
              style={{
                padding: 24,
                textAlign: "center",
                color: "var(--color-text-dim)",
                fontSize: 13,
                border: "1px dashed var(--color-border)",
                borderRadius: "var(--radius-sm)",
              }}
            >
              <p style={{ marginBottom: 4 }}>
                Full version history is available via the{" "}
                <code style={{ fontFamily: "var(--font-mono)", color: "var(--color-n8n)" }}>
                  n8n_workflow_versions
                </code>{" "}
                endpoint.
              </p>
              <p style={{ color: "var(--color-text-dim)", fontSize: 12 }}>
                Ask me to fetch version history for workflow {data.id}
              </p>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ─── Toast Component ─────────────────────────────────────────── */

function Toast({
  message,
  type,
  onDone,
}: {
  message: string;
  type: "success" | "error";
  onDone: () => void;
}) {
  React.useEffect(() => {
    const t = setTimeout(onDone, 3000);
    return () => clearTimeout(t);
  }, [onDone]);

  return <div className={`toast ${type}`}>{message}</div>;
}

/* ─── Main App ────────────────────────────────────────────────── */

function WorkflowDetailApp() {
  const [workflow, setWorkflow] = useState<WorkflowData | null>(null);
  const [activeTab, setActiveTab] = useState<TabId>("overview");
  const [toast, setToast] = useState<{ message: string; type: "success" | "error" } | null>(null);
  const [loading, setLoading] = useState(true);

  const { app, isConnected, error } = useApp({
    appInfo: { name: "n8n-workflow-detail", version: "1.0.0" },
    capabilities: {},
    onAppCreated: (app) => {
      app.ontoolresult = (params) => {
        if (params.isError) {
          setLoading(false);
          setToast({ message: "Failed to load workflow data", type: "error" });
          return;
        }
        try {
          const textContent = params.content?.find(
            (c: { type: string }) => c.type === "text"
          ) as { type: "text"; text: string } | undefined;
          if (textContent?.text) {
            const parsed = JSON.parse(textContent.text);
            setWorkflow(parsed);
          }
        } catch {
          setToast({ message: "Invalid workflow data", type: "error" });
        }
        setLoading(false);
      };

      app.ontoolinput = () => {
        setLoading(true);
      };
    },
  });

  useHostStyles(app, app?.getHostContext());

  const handleAction = useCallback(
    async (action: string) => {
      if (!app || !workflow) return;
      const caps = app.getHostCapabilities();
      if (caps?.messages) {
        try {
          await app.sendMessage({
            text: `${action} workflow ${workflow.id}`,
          });
          setToast({ message: `Sent: "${action} workflow ${workflow.id}"`, type: "success" });
        } catch {
          setToast({ message: "Failed to send message", type: "error" });
        }
      } else {
        setToast({ message: `Action: ${action} workflow ${workflow.id}`, type: "success" });
      }
    },
    [app, workflow]
  );

  const handleOpenInN8n = useCallback(async () => {
    if (!app || !workflow) return;
    try {
      await app.openLink({ url: `https://auto.localbosses.org/workflow/${workflow.id}` });
    } catch {
      setToast({ message: "Could not open link", type: "error" });
    }
  }, [app, workflow]);

  // Error state
  if (error) {
    return (
      <div className="page">
        <div className="empty-state">
          <div className="icon">⚠️</div>
          <h3>Connection Error</h3>
          <p>{error.message}</p>
        </div>
      </div>
    );
  }

  // Loading state
  if (!isConnected || loading || !workflow) {
    return (
      <div className="page">
        <div className="empty-state">
          <div className="spinner"></div>
          <h3 style={{ marginTop: 16 }}>Loading Workflow…</h3>
          <p>Fetching workflow data from n8n</p>
        </div>
      </div>
    );
  }

  const tabs: { id: TabId; label: string; icon: string }[] = [
    { id: "overview", label: "Overview", icon: "📊" },
    { id: "nodes", label: "Nodes", icon: "⚙️" },
    { id: "connections", label: "Connections", icon: "🔗" },
    { id: "settings", label: "Settings", icon: "🛠" },
    { id: "versions", label: "Versions", icon: "📋" },
  ];

  return (
    <div className="page">
      {/* Header */}
      <div className="page-header">
        <div>
          <div className="page-title">
            <span className="icon">⚡</span>
            <span>{workflow.name}</span>
            <span className={`badge ${workflow.active ? "active" : "inactive"}`}>
              {workflow.active ? "● Active" : "○ Inactive"}
            </span>
          </div>
          <div className="page-subtitle">
            ID: {workflow.id} &nbsp;·&nbsp; Created: {formatDate(workflow.createdAt)}
            &nbsp;·&nbsp; Updated: {formatDate(workflow.updatedAt)}
          </div>
        </div>
        <div className="page-actions">
          <button className="btn btn-secondary btn-sm" onClick={handleOpenInN8n}>
            ↗ Open in n8n
          </button>
          <button
            className="btn btn-secondary btn-sm"
            onClick={() => handleAction("Validate")}
          >
            ✓ Validate
          </button>
          <button
            className="btn btn-secondary btn-sm"
            onClick={() => handleAction("Test")}
          >
            ▶ Test
          </button>
          <button
            className="btn btn-primary btn-sm"
            onClick={() => handleAction("Duplicate")}
          >
            ⧉ Duplicate
          </button>
        </div>
      </div>

      {/* Tabs */}
      <div className="tabs">
        {tabs.map((t) => (
          <button
            key={t.id}
            className={`tab${activeTab === t.id ? " active" : ""}`}
            onClick={() => setActiveTab(t.id)}
          >
            {t.icon} {t.label}
          </button>
        ))}
      </div>

      {/* Tab Content */}
      {activeTab === "overview" && <OverviewTab data={workflow} />}
      {activeTab === "nodes" && <NodesTab data={workflow} />}
      {activeTab === "connections" && <ConnectionsTab data={workflow} />}
      {activeTab === "settings" && <SettingsTab data={workflow} />}
      {activeTab === "versions" && <VersionsTab data={workflow} />}

      {/* Toast */}
      {toast && (
        <Toast
          message={toast.message}
          type={toast.type}
          onDone={() => setToast(null)}
        />
      )}
    </div>
  );
}

/* ─── Mount ───────────────────────────────────────────────────── */

const root = createRoot(document.getElementById("root")!);
root.render(<WorkflowDetailApp />);
