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

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

interface Execution {
  id: string;
  finished: boolean;
  mode: string;
  startedAt: string;
  stoppedAt: string | null;
  workflowId: string;
  status: "success" | "error" | "running" | "waiting" | "unknown";
  waitTill: string | null;
}

interface ExecutionData {
  data: Execution[];
  nextCursor: string | null;
}

type StatusFilter = "all" | "success" | "error" | "running" | "waiting";

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

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

function calcDuration(started: string, stopped: string | null): string {
  if (!started) return "—";
  const start = new Date(started).getTime();
  if (!stopped) return "Running…";
  const end = new Date(stopped).getTime();
  const diffMs = end - start;
  if (diffMs < 0) return "—";
  if (diffMs < 1000) return `${diffMs}ms`;
  if (diffMs < 60000) return `${(diffMs / 1000).toFixed(1)}s`;
  const mins = Math.floor(diffMs / 60000);
  const secs = Math.floor((diffMs % 60000) / 1000);
  return `${mins}m ${secs}s`;
}

function calcDurationMs(started: string, stopped: string | null): number {
  if (!started || !stopped) return 0;
  return Math.max(0, new Date(stopped).getTime() - new Date(started).getTime());
}

function statusBadgeClass(status: string): string {
  switch (status) {
    case "success":
      return "active";
    case "error":
      return "error";
    case "running":
      return "running";
    case "waiting":
      return "n8n";
    default:
      return "inactive";
  }
}

function statusIcon(status: string): string {
  switch (status) {
    case "success":
      return "✓";
    case "error":
      return "✗";
    case "running":
      return "⟳";
    case "waiting":
      return "⏳";
    default:
      return "?";
  }
}

function formatAvgDuration(ms: number): string {
  if (ms === 0) return "—";
  if (ms < 1000) return `${Math.round(ms)}ms`;
  if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
  const mins = Math.floor(ms / 60000);
  const secs = Math.floor((ms % 60000) / 1000);
  return `${mins}m ${secs}s`;
}

/* ─── Stats Component ─────────────────────────────────────────── */

function StatsRow({ executions }: { executions: Execution[] }) {
  const stats = useMemo(() => {
    const total = executions.length;
    const success = executions.filter((e) => e.status === "success").length;
    const errors = executions.filter((e) => e.status === "error").length;
    const running = executions.filter((e) => e.status === "running").length;

    const durations = executions
      .filter((e) => e.startedAt && e.stoppedAt)
      .map((e) => calcDurationMs(e.startedAt, e.stoppedAt));
    const avgMs =
      durations.length > 0
        ? durations.reduce((a, b) => a + b, 0) / durations.length
        : 0;

    return { total, success, errors, running, avgMs };
  }, [executions]);

  return (
    <div className="stats-row">
      <div className="stat-card accent">
        <div className="stat-value">{stats.total}</div>
        <div className="stat-label">Total Executions</div>
      </div>
      <div className="stat-card success">
        <div className="stat-value">{stats.success}</div>
        <div className="stat-label">Successful</div>
      </div>
      <div className="stat-card error">
        <div className="stat-value">{stats.errors}</div>
        <div className="stat-label">Errors</div>
      </div>
      <div className="stat-card" style={{ borderColor: stats.running > 0 ? "var(--color-info)" : undefined }}>
        <div className="stat-value" style={{ color: stats.running > 0 ? "var(--color-info)" : undefined }}>
          {stats.running}
        </div>
        <div className="stat-label">Running</div>
      </div>
      <div className="stat-card">
        <div className="stat-value" style={{ fontSize: 20 }}>
          {formatAvgDuration(stats.avgMs)}
        </div>
        <div className="stat-label">Avg Duration</div>
      </div>
    </div>
  );
}

/* ─── Filter Bar ──────────────────────────────────────────────── */

function FilterBar({
  workflowFilter,
  setWorkflowFilter,
  statusFilter,
  setStatusFilter,
  autoRefresh,
  setAutoRefresh,
}: {
  workflowFilter: string;
  setWorkflowFilter: (v: string) => void;
  statusFilter: StatusFilter;
  setStatusFilter: (v: StatusFilter) => void;
  autoRefresh: boolean;
  setAutoRefresh: (v: boolean) => void;
}) {
  return (
    <div
      style={{
        display: "flex",
        gap: 12,
        marginBottom: 20,
        flexWrap: "wrap",
        alignItems: "center",
      }}
    >
      <div style={{ flex: "1 1 200px", maxWidth: 280 }}>
        <input
          className="input"
          type="text"
          placeholder="Filter by Workflow ID…"
          value={workflowFilter}
          onChange={(e) => setWorkflowFilter(e.target.value)}
        />
      </div>
      <div style={{ flex: "0 0 auto" }}>
        <select
          className="select"
          style={{ width: "auto", minWidth: 140 }}
          value={statusFilter}
          onChange={(e) => setStatusFilter(e.target.value as StatusFilter)}
        >
          <option value="all">All Statuses</option>
          <option value="success">✓ Success</option>
          <option value="error">✗ Error</option>
          <option value="running">⟳ Running</option>
          <option value="waiting">⏳ Waiting</option>
        </select>
      </div>
      <div style={{ marginLeft: "auto", flex: "0 0 auto" }}>
        <button
          className={`btn btn-sm ${autoRefresh ? "btn-primary" : "btn-secondary"}`}
          onClick={() => setAutoRefresh(!autoRefresh)}
        >
          {autoRefresh ? "⟳ Auto-refresh ON" : "⟳ Auto-refresh OFF"}
        </button>
      </div>
    </div>
  );
}

/* ─── Expanded Row ────────────────────────────────────────────── */

function ExpandedRow({ execution }: { execution: Execution }) {
  return (
    <tr>
      <td colSpan={6} 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: 12,
            }}
          >
            Execution Details
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(200px, 1fr))", gap: 16 }}>
            <div>
              <div style={{ fontSize: 11, color: "var(--color-text-dim)", textTransform: "uppercase", letterSpacing: 0.5, marginBottom: 2 }}>
                Execution ID
              </div>
              <div style={{ fontFamily: "var(--font-mono)", fontSize: 13 }}>{execution.id}</div>
            </div>
            <div>
              <div style={{ fontSize: 11, color: "var(--color-text-dim)", textTransform: "uppercase", letterSpacing: 0.5, marginBottom: 2 }}>
                Workflow ID
              </div>
              <div style={{ fontFamily: "var(--font-mono)", fontSize: 13 }}>{execution.workflowId}</div>
            </div>
            <div>
              <div style={{ fontSize: 11, color: "var(--color-text-dim)", textTransform: "uppercase", letterSpacing: 0.5, marginBottom: 2 }}>
                Mode
              </div>
              <div style={{ fontSize: 13 }}>{execution.mode}</div>
            </div>
            <div>
              <div style={{ fontSize: 11, color: "var(--color-text-dim)", textTransform: "uppercase", letterSpacing: 0.5, marginBottom: 2 }}>
                Finished
              </div>
              <div style={{ fontSize: 13 }}>{execution.finished ? "Yes" : "No"}</div>
            </div>
            <div>
              <div style={{ fontSize: 11, color: "var(--color-text-dim)", textTransform: "uppercase", letterSpacing: 0.5, marginBottom: 2 }}>
                Started At
              </div>
              <div style={{ fontSize: 13 }}>{formatDate(execution.startedAt)}</div>
            </div>
            <div>
              <div style={{ fontSize: 11, color: "var(--color-text-dim)", textTransform: "uppercase", letterSpacing: 0.5, marginBottom: 2 }}>
                Stopped At
              </div>
              <div style={{ fontSize: 13 }}>{formatDate(execution.stoppedAt)}</div>
            </div>
            <div>
              <div style={{ fontSize: 11, color: "var(--color-text-dim)", textTransform: "uppercase", letterSpacing: 0.5, marginBottom: 2 }}>
                Duration
              </div>
              <div style={{ fontSize: 13, fontWeight: 600 }}>
                {calcDuration(execution.startedAt, execution.stoppedAt)}
              </div>
            </div>
            {execution.waitTill && (
              <div>
                <div style={{ fontSize: 11, color: "var(--color-text-dim)", textTransform: "uppercase", letterSpacing: 0.5, marginBottom: 2 }}>
                  Wait Until
                </div>
                <div style={{ fontSize: 13 }}>{formatDate(execution.waitTill)}</div>
              </div>
            )}
          </div>
        </div>
      </td>
    </tr>
  );
}

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

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

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

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

function ExecutionDashboardApp() {
  const [allExecutions, setAllExecutions] = useState<Execution[]>([]);
  const [nextCursor, setNextCursor] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);
  const [loadingMore, setLoadingMore] = useState(false);
  const [expandedId, setExpandedId] = useState<string | null>(null);
  const [toast, setToast] = useState<{ message: string; type: "success" | "error" } | null>(null);

  // Filters — client-side only
  const [workflowFilter, setWorkflowFilter] = useState("");
  const [statusFilter, setStatusFilter] = useState<StatusFilter>("all");
  const [autoRefresh, setAutoRefresh] = useState(false);

  // Simulated auto-refresh pulse
  const [refreshCount, setRefreshCount] = useState(0);

  useEffect(() => {
    if (!autoRefresh) return;
    const interval = setInterval(() => {
      setRefreshCount((c) => c + 1);
    }, 5000);
    return () => clearInterval(interval);
  }, [autoRefresh]);

  const { app, isConnected, error } = useApp({
    appInfo: { name: "n8n-execution-dashboard", version: "1.0.0" },
    capabilities: {},
    onAppCreated: (app) => {
      app.ontoolresult = (params) => {
        if (params.isError) {
          setLoading(false);
          setLoadingMore(false);
          setToast({ message: "Failed to load execution 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: ExecutionData = JSON.parse(textContent.text);
            const executions = (parsed.data || []).map((e) => ({
              ...e,
              status: e.status || (e.finished ? "success" : "running"),
            })) as Execution[];

            // If loadingMore, append; otherwise replace
            setAllExecutions((prev) => {
              if (loadingMore) {
                // Deduplicate by id
                const existingIds = new Set(prev.map((x) => x.id));
                const newItems = executions.filter((x) => !existingIds.has(x.id));
                return [...prev, ...newItems];
              }
              return executions;
            });
            setNextCursor(parsed.nextCursor || null);
          }
        } catch {
          setToast({ message: "Invalid execution data", type: "error" });
        }
        setLoading(false);
        setLoadingMore(false);
      };

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

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

  // Client-side filtering
  const filteredExecutions = useMemo(() => {
    let filtered = allExecutions;
    if (workflowFilter.trim()) {
      const q = workflowFilter.trim().toLowerCase();
      filtered = filtered.filter(
        (e) =>
          e.workflowId.toLowerCase().includes(q) ||
          e.id.toLowerCase().includes(q)
      );
    }
    if (statusFilter !== "all") {
      filtered = filtered.filter((e) => e.status === statusFilter);
    }
    return filtered;
  }, [allExecutions, workflowFilter, statusFilter]);

  // Load more via server tool
  const handleLoadMore = useCallback(async () => {
    if (!app || !nextCursor) return;
    const caps = app.getHostCapabilities();
    if (!caps?.serverTools) {
      setToast({ message: "Server tool calls not supported by host", type: "error" });
      return;
    }
    setLoadingMore(true);
    try {
      const result = await app.callServerTool({
        name: "n8n_execution_dashboard",
        arguments: { cursor: nextCursor },
      });
      // Result will be delivered via ontoolresult
      if (result.isError) {
        setToast({ message: "Failed to load more executions", type: "error" });
        setLoadingMore(false);
      }
    } catch {
      setToast({ message: "Error calling server tool", type: "error" });
      setLoadingMore(false);
    }
  }, [app, nextCursor]);

  // 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) {
    return (
      <div className="page">
        <div className="empty-state">
          <div className="spinner"></div>
          <h3 style={{ marginTop: 16 }}>Loading Executions…</h3>
          <p>Fetching execution data from n8n</p>
        </div>
      </div>
    );
  }

  return (
    <div className="page">
      {/* Header */}
      <div className="page-header">
        <div>
          <div className="page-title">
            <span className="icon">📊</span>
            <span>Execution Dashboard</span>
            {autoRefresh && (
              <span
                className="badge running"
                style={{ fontSize: 10, padding: "2px 8px" }}
              >
                LIVE
              </span>
            )}
          </div>
          <div className="page-subtitle">
            {allExecutions.length} execution{allExecutions.length !== 1 ? "s" : ""} loaded
            {nextCursor && " · more available"}
            {autoRefresh && ` · refreshed ${refreshCount}×`}
          </div>
        </div>
      </div>

      {/* Stats */}
      <StatsRow executions={allExecutions} />

      {/* Filters */}
      <FilterBar
        workflowFilter={workflowFilter}
        setWorkflowFilter={setWorkflowFilter}
        statusFilter={statusFilter}
        setStatusFilter={setStatusFilter}
        autoRefresh={autoRefresh}
        setAutoRefresh={setAutoRefresh}
      />

      {/* Table or Empty */}
      {filteredExecutions.length === 0 ? (
        <div className="empty-state">
          <div className="icon">📭</div>
          <h3>No Executions Found</h3>
          <p>
            {allExecutions.length === 0
              ? "No workflow executions have been recorded yet."
              : "No executions match your current filters. Try adjusting the workflow ID or status filter."}
          </p>
        </div>
      ) : (
        <div className="card">
          <div className="table-wrap">
            <table>
              <thead>
                <tr>
                  <th>ID</th>
                  <th>Workflow</th>
                  <th>Status</th>
                  <th>Started</th>
                  <th>Duration</th>
                  <th>Mode</th>
                </tr>
              </thead>
              <tbody>
                {filteredExecutions.map((exec) => (
                  <React.Fragment key={exec.id}>
                    <tr
                      onClick={() =>
                        setExpandedId(expandedId === exec.id ? null : exec.id)
                      }
                      style={{ cursor: "pointer" }}
                    >
                      <td>
                        <span
                          style={{
                            fontFamily: "var(--font-mono)",
                            fontSize: 12,
                            color: "var(--color-n8n)",
                          }}
                        >
                          {exec.id}
                        </span>
                      </td>
                      <td>
                        <span
                          style={{
                            fontFamily: "var(--font-mono)",
                            fontSize: 12,
                          }}
                        >
                          {exec.workflowId}
                        </span>
                      </td>
                      <td>
                        <span className={`badge ${statusBadgeClass(exec.status)}`}>
                          {statusIcon(exec.status)} {exec.status}
                        </span>
                      </td>
                      <td>{formatDate(exec.startedAt)}</td>
                      <td>
                        <span
                          style={{
                            fontWeight: 600,
                            color:
                              exec.status === "running"
                                ? "var(--color-info)"
                                : "var(--color-text)",
                          }}
                        >
                          {calcDuration(exec.startedAt, exec.stoppedAt)}
                        </span>
                      </td>
                      <td>
                        <span style={{ fontSize: 12, color: "var(--color-text-muted)" }}>
                          {exec.mode}
                        </span>
                      </td>
                    </tr>
                    {expandedId === exec.id && <ExpandedRow execution={exec} />}
                  </React.Fragment>
                ))}
              </tbody>
            </table>
          </div>

          {/* Load More */}
          {nextCursor && (
            <div className="card-footer" style={{ justifyContent: "center" }}>
              <button
                className="btn btn-secondary"
                onClick={handleLoadMore}
                disabled={loadingMore}
              >
                {loadingMore ? (
                  <>
                    <span className="spinner" style={{ width: 14, height: 14 }}></span>
                    Loading…
                  </>
                ) : (
                  "Load More Executions"
                )}
              </button>
            </div>
          )}
        </div>
      )}

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

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

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