import { useState, useEffect, useCallback, useRef } from "react";
import { SimpleDiffEditor } from "../components/editor/SimpleEditor";
import { api } from "../services/api";
import { useWebSocket } from "../hooks/useWebSocket";
import {
  Eye,
  EyeOff,
  FileCode,
  Check,
  X,
  RefreshCw,
  Trash2,
  ArrowUpCircle,
} from "lucide-react";

interface ChangeEntry {
  filename: string;
  gffType: string;
  repoPath: string | null;
  timestamp: number;
}

interface DiffData {
  original: string;
  modified: string;
  filename: string;
}

function formatTimestamp(ts: number): string {
  return new Date(ts).toLocaleTimeString();
}

export function Toolset() {
  const { subscribe } = useWebSocket();
  const [active, setActive] = useState(false);
  const [changes, setChanges] = useState<ChangeEntry[]>([]);
  const [selected, setSelected] = useState<Set<string>>(new Set());
  const [diffData, setDiffData] = useState<DiffData | null>(null);
  const [loading, setLoading] = useState(false);
  const [lastChange, setLastChange] = useState<number | null>(null);
  const diffContainerRef = useRef<HTMLDivElement>(null);

  const refresh = useCallback(async () => {
    try {
      const status = await api.toolset.status();
      setActive(status.active);
      const list = await api.toolset.changes();
      setChanges(list);
      if (list.length > 0) {
        setLastChange(Math.max(...list.map((c) => c.timestamp)));
      }
    } catch {
      // backend may not be reachable yet
    }
  }, []);

  useEffect(() => {
    refresh();
  }, [refresh]);

  useEffect(() => {
    const unsubs = [
      subscribe("toolset:change", (event) => {
        const data = event.data as ChangeEntry;
        setChanges((prev) => {
          const idx = prev.findIndex((c) => c.filename === data.filename);
          if (idx >= 0) {
            const next = [...prev];
            next[idx] = data;
            return next;
          }
          return [...prev, data];
        });
        setLastChange(data.timestamp);
      }),
      subscribe("toolset:applied", (event) => {
        const { filename } = event.data as { filename: string };
        setChanges((prev) => prev.filter((c) => c.filename !== filename));
        setSelected((prev) => {
          const next = new Set(prev);
          next.delete(filename);
          return next;
        });
        if (diffData?.filename === filename) setDiffData(null);
      }),
      subscribe("toolset:discarded", (event) => {
        const { filename } = event.data as { filename: string };
        setChanges((prev) => prev.filter((c) => c.filename !== filename));
        setSelected((prev) => {
          const next = new Set(prev);
          next.delete(filename);
          return next;
        });
        if (diffData?.filename === filename) setDiffData(null);
      }),
      subscribe("toolset:discarded-all", () => {
        setChanges([]);
        setSelected(new Set());
        setDiffData(null);
      }),
      subscribe("toolset:watcher:started", () => setActive(true)),
      subscribe("toolset:watcher:stopped", () => setActive(false)),
    ];
    return () => unsubs.forEach((u) => u());
  }, [subscribe, diffData?.filename]);

  const toggleSelect = (filename: string) => {
    setSelected((prev) => {
      const next = new Set(prev);
      if (next.has(filename)) next.delete(filename);
      else next.add(filename);
      return next;
    });
  };

  const toggleAll = () => {
    if (selected.size === changes.length) {
      setSelected(new Set());
    } else {
      setSelected(new Set(changes.map((c) => c.filename)));
    }
  };

  const viewDiff = async (change: ChangeEntry) => {
    setLoading(true);
    try {
      const full = await api.toolset.getChange(change.filename);
      let original = "";
      if (change.repoPath) {
        try {
          const { content } = await api.editor.readFile(
            "nwn-module",
            change.repoPath,
          );
          original = content;
        } catch {
          // file doesn't exist in repo yet
        }
      }
      setDiffData({
        original,
        modified: full.jsonContent ?? "",
        filename: change.filename,
      });
    } catch (err) {
      console.error("Failed to load diff:", err);
    } finally {
      setLoading(false);
    }
  };

  const handleStart = async () => {
    await api.toolset.start();
    setActive(true);
  };

  const handleStop = async () => {
    await api.toolset.stop();
    setActive(false);
  };

  const handleApplySelected = async () => {
    if (selected.size === 0) return;
    await api.toolset.apply(Array.from(selected));
    refresh();
  };

  const handleApplyAll = async () => {
    await api.toolset.applyAll();
    refresh();
  };

  const handleDiscardSelected = async () => {
    if (selected.size === 0) return;
    await api.toolset.discard(Array.from(selected));
    refresh();
  };

  const handleDiscardAll = async () => {
    if (!window.confirm("Discard all changes? This cannot be undone.")) return;
    await api.toolset.discardAll();
    refresh();
  };

  return (
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        height: "100%",
        overflow: "hidden",
        color: "var(--forge-text)",
      }}
    >
      {/* Page heading */}
      <div style={{ padding: "24px 28px 0" }}>
        <h1
          style={{
            fontFamily: "var(--font-heading)",
            fontSize: "var(--text-xl)",
            fontWeight: 700,
            color: "var(--forge-text)",
            margin: 0,
          }}
        >
          Toolset
        </h1>
        <p
          style={{
            fontSize: "var(--text-sm)",
            color: "var(--forge-text-secondary)",
            margin: "4px 0 0",
          }}
        >
          Watch for NWN Toolset changes and apply them to the repository
        </p>
      </div>

      {/* Watcher status card */}
      <div style={{ padding: "16px 28px" }}>
        <div
          style={{
            backgroundColor: "var(--forge-surface)",
            border: "1px solid var(--forge-border)",
            borderRadius: 8,
            padding: "16px 20px",
            display: "flex",
            alignItems: "center",
            justifyContent: "space-between",
          }}
        >
          <div
            style={{ display: "flex", alignItems: "center", gap: 16 }}
          >
            <div
              style={{ display: "flex", alignItems: "center", gap: 8 }}
            >
              {active ? (
                <Eye size={16} style={{ color: "var(--forge-success)" }} />
              ) : (
                <EyeOff
                  size={16}
                  style={{ color: "var(--forge-text-secondary)" }}
                />
              )}
              <span
                style={{
                  display: "inline-flex",
                  alignItems: "center",
                  gap: 6,
                  padding: "3px 10px",
                  borderRadius: 999,
                  fontSize: "var(--text-xs)",
                  fontWeight: 600,
                  backgroundColor: active
                    ? "var(--forge-success-bg)"
                    : "var(--forge-surface-raised)",
                  color: active
                    ? "var(--forge-success)"
                    : "var(--forge-text-secondary)",
                }}
              >
                {active ? "Active" : "Inactive"}
              </span>
            </div>
            <span
              style={{
                fontSize: "var(--text-xs)",
                color: "var(--forge-text-secondary)",
              }}
            >
              {changes.length} pending change{changes.length !== 1 && "s"}
            </span>
            {lastChange && (
              <span
                style={{
                  fontSize: "var(--text-xs)",
                  color: "var(--forge-text-secondary)",
                }}
              >
                Last change: {formatTimestamp(lastChange)}
              </span>
            )}
          </div>

          <button
            onClick={active ? handleStop : handleStart}
            style={{
              display: "inline-flex",
              alignItems: "center",
              gap: 6,
              padding: "6px 14px",
              borderRadius: 6,
              border: "1px solid",
              fontSize: "var(--text-sm)",
              fontWeight: 500,
              cursor: "pointer",
              backgroundColor: active
                ? "var(--forge-surface)"
                : "var(--forge-accent)",
              borderColor: active
                ? "var(--forge-border)"
                : "var(--forge-accent)",
              color: active
                ? "var(--forge-text)"
                : "var(--forge-accent-text)",
            }}
          >
            {active ? (
              <>
                <EyeOff size={14} />
                Stop Watcher
              </>
            ) : (
              <>
                <Eye size={14} />
                Start Watcher
              </>
            )}
          </button>
        </div>
      </div>

      {/* Main content area */}
      <div
        style={{
          flex: 1,
          minHeight: 0,
          display: "flex",
          flexDirection: "column",
          overflow: "hidden",
          padding: "0 28px 20px",
        }}
      >
        {/* Changes card */}
        <div
          style={{
            backgroundColor: "var(--forge-surface)",
            border: "1px solid var(--forge-border)",
            borderRadius: 8,
            overflow: "hidden",
            display: "flex",
            flexDirection: "column",
            flex: diffData ? "0 0 auto" : 1,
            maxHeight: diffData ? "40%" : undefined,
          }}
        >
          {/* Card header with action bar */}
          <div
            style={{
              display: "flex",
              alignItems: "center",
              justifyContent: "space-between",
              padding: "12px 16px",
              borderBottom: "1px solid var(--forge-border)",
              backgroundColor: "var(--forge-surface-raised)",
            }}
          >
            <div
              style={{ display: "flex", alignItems: "center", gap: 8 }}
            >
              <FileCode
                size={16}
                style={{ color: "var(--forge-accent)" }}
              />
              <span
                style={{
                  fontSize: "var(--text-sm)",
                  fontWeight: 600,
                  color: "var(--forge-text)",
                }}
              >
                Pending Changes
              </span>
              {changes.length > 0 && (
                <span
                  style={{
                    fontSize: "var(--text-xs)",
                    color: "var(--forge-text-secondary)",
                    marginLeft: 4,
                  }}
                >
                  {selected.size} of {changes.length} selected
                </span>
              )}
            </div>

            {changes.length > 0 && (
              <div
                style={{ display: "flex", alignItems: "center", gap: 6 }}
              >
                <button
                  onClick={handleApplySelected}
                  disabled={selected.size === 0}
                  style={{
                    display: "inline-flex",
                    alignItems: "center",
                    gap: 5,
                    padding: "5px 12px",
                    borderRadius: 5,
                    border: "none",
                    fontSize: "var(--text-xs)",
                    fontWeight: 500,
                    cursor: selected.size === 0 ? "not-allowed" : "pointer",
                    opacity: selected.size === 0 ? 0.5 : 1,
                    backgroundColor: "var(--forge-accent)",
                    color: "var(--forge-accent-text)",
                  }}
                >
                  <Check size={12} />
                  Apply Selected
                </button>
                <button
                  onClick={handleApplyAll}
                  style={{
                    display: "inline-flex",
                    alignItems: "center",
                    gap: 5,
                    padding: "5px 12px",
                    borderRadius: 5,
                    border: "1px solid var(--forge-accent)",
                    fontSize: "var(--text-xs)",
                    fontWeight: 500,
                    cursor: "pointer",
                    backgroundColor: "transparent",
                    color: "var(--forge-accent)",
                  }}
                >
                  <ArrowUpCircle size={12} />
                  Apply All
                </button>
                <button
                  onClick={handleDiscardSelected}
                  disabled={selected.size === 0}
                  style={{
                    display: "inline-flex",
                    alignItems: "center",
                    gap: 5,
                    padding: "5px 12px",
                    borderRadius: 5,
                    border: "none",
                    fontSize: "var(--text-xs)",
                    fontWeight: 500,
                    cursor: selected.size === 0 ? "not-allowed" : "pointer",
                    opacity: selected.size === 0 ? 0.5 : 1,
                    backgroundColor: "var(--forge-danger-bg)",
                    color: "var(--forge-danger)",
                  }}
                >
                  <Trash2 size={12} />
                  Discard Selected
                </button>
                <button
                  onClick={handleDiscardAll}
                  style={{
                    display: "inline-flex",
                    alignItems: "center",
                    gap: 5,
                    padding: "5px 12px",
                    borderRadius: 5,
                    border: "1px solid var(--forge-danger-border)",
                    fontSize: "var(--text-xs)",
                    fontWeight: 500,
                    cursor: "pointer",
                    backgroundColor: "transparent",
                    color: "var(--forge-danger)",
                  }}
                >
                  <X size={12} />
                  Discard All
                </button>
              </div>
            )}
          </div>

          {/* Table or empty state */}
          <div style={{ overflow: "auto", flex: 1 }}>
            {changes.length === 0 ? (
              <div
                style={{
                  display: "flex",
                  flexDirection: "column",
                  alignItems: "center",
                  justifyContent: "center",
                  padding: "48px 24px",
                  color: "var(--forge-text-secondary)",
                }}
              >
                {active ? (
                  <>
                    <RefreshCw
                      size={28}
                      style={{
                        marginBottom: 12,
                        opacity: 0.4,
                        animation: "spin 3s linear infinite",
                      }}
                    />
                    <span style={{ fontSize: "var(--text-sm)" }}>
                      Watching for changes in temp0/...
                    </span>
                  </>
                ) : (
                  <>
                    <EyeOff
                      size={28}
                      style={{ marginBottom: 12, opacity: 0.4 }}
                    />
                    <span style={{ fontSize: "var(--text-sm)" }}>
                      Start the watcher to detect Toolset changes
                    </span>
                  </>
                )}
              </div>
            ) : (
              <table
                style={{
                  width: "100%",
                  fontSize: "var(--text-sm)",
                  borderCollapse: "collapse",
                }}
              >
                <thead>
                  <tr
                    style={{
                      borderBottom: "1px solid var(--forge-border)",
                      backgroundColor: "var(--forge-surface-raised)",
                      color: "var(--forge-text-secondary)",
                    }}
                  >
                    <th
                      style={{
                        padding: "8px 16px",
                        textAlign: "left",
                        fontWeight: 500,
                        width: 40,
                      }}
                    >
                      <input
                        type="checkbox"
                        checked={
                          selected.size === changes.length &&
                          changes.length > 0
                        }
                        onChange={toggleAll}
                        style={{ cursor: "pointer" }}
                      />
                    </th>
                    <th
                      style={{
                        padding: "8px 10px",
                        textAlign: "left",
                        fontWeight: 500,
                      }}
                    >
                      Filename
                    </th>
                    <th
                      style={{
                        padding: "8px 10px",
                        textAlign: "left",
                        fontWeight: 500,
                      }}
                    >
                      Type
                    </th>
                    <th
                      style={{
                        padding: "8px 10px",
                        textAlign: "left",
                        fontWeight: 500,
                      }}
                    >
                      Repo Path
                    </th>
                    <th
                      style={{
                        padding: "8px 10px",
                        textAlign: "left",
                        fontWeight: 500,
                      }}
                    >
                      Time
                    </th>
                  </tr>
                </thead>
                <tbody>
                  {changes.map((change) => (
                    <tr
                      key={change.filename}
                      onClick={() => viewDiff(change)}
                      style={{
                        borderBottom: "1px solid var(--forge-border)",
                        cursor: "pointer",
                        backgroundColor:
                          diffData?.filename === change.filename
                            ? "var(--forge-accent-subtle)"
                            : undefined,
                      }}
                    >
                      <td style={{ padding: "8px 16px" }}>
                        <input
                          type="checkbox"
                          checked={selected.has(change.filename)}
                          onChange={(e) => {
                            e.stopPropagation();
                            toggleSelect(change.filename);
                          }}
                          onClick={(e) => e.stopPropagation()}
                          style={{ cursor: "pointer" }}
                        />
                      </td>
                      <td
                        style={{
                          padding: "8px 10px",
                          fontFamily: "var(--font-mono)",
                          color: "var(--forge-text)",
                        }}
                      >
                        {change.filename}
                      </td>
                      <td style={{ padding: "8px 10px" }}>
                        <span
                          style={{
                            display: "inline-block",
                            padding: "2px 8px",
                            borderRadius: 4,
                            fontSize: "var(--text-xs)",
                            fontWeight: 500,
                            backgroundColor: "var(--forge-accent-subtle)",
                            color: "var(--forge-accent)",
                          }}
                        >
                          {change.gffType}
                        </span>
                      </td>
                      <td
                        style={{
                          padding: "8px 10px",
                          fontFamily: "var(--font-mono)",
                          fontSize: "var(--text-xs)",
                          color: "var(--forge-text-secondary)",
                        }}
                      >
                        {change.repoPath ?? "—"}
                      </td>
                      <td
                        style={{
                          padding: "8px 10px",
                          fontSize: "var(--text-xs)",
                          color: "var(--forge-text-secondary)",
                        }}
                      >
                        {formatTimestamp(change.timestamp)}
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            )}
          </div>
        </div>

        {/* Diff viewer panel */}
        {diffData && (
          <div
            ref={diffContainerRef}
            style={{
              flex: 1,
              minHeight: 0,
              display: "flex",
              flexDirection: "column",
              marginTop: 16,
              backgroundColor: "var(--forge-surface)",
              border: "1px solid var(--forge-border)",
              borderRadius: 8,
              overflow: "hidden",
            }}
          >
            {/* Diff header */}
            <div
              style={{
                display: "flex",
                alignItems: "center",
                justifyContent: "space-between",
                padding: "10px 16px",
                backgroundColor: "var(--forge-surface-raised)",
                borderBottom: "1px solid var(--forge-border)",
              }}
            >
              <div
                style={{
                  display: "flex",
                  alignItems: "center",
                  gap: 8,
                }}
              >
                <FileCode
                  size={14}
                  style={{ color: "var(--forge-accent)" }}
                />
                <span
                  style={{
                    fontSize: "var(--text-sm)",
                    fontWeight: 600,
                    fontFamily: "var(--font-mono)",
                    color: "var(--forge-text)",
                  }}
                >
                  {diffData.filename}
                </span>
                {loading && (
                  <span
                    style={{
                      fontSize: "var(--text-xs)",
                      color: "var(--forge-text-secondary)",
                    }}
                  >
                    Loading...
                  </span>
                )}
              </div>
              <button
                onClick={() => setDiffData(null)}
                style={{
                  display: "inline-flex",
                  alignItems: "center",
                  gap: 4,
                  padding: "4px 10px",
                  borderRadius: 5,
                  border: "1px solid var(--forge-border)",
                  fontSize: "var(--text-xs)",
                  fontWeight: 500,
                  cursor: "pointer",
                  backgroundColor: "var(--forge-surface)",
                  color: "var(--forge-text-secondary)",
                }}
              >
                <X size={12} />
                Close
              </button>
            </div>

            {/* Diff content */}
            <div
              style={{
                flex: 1,
                minHeight: 0,
                backgroundColor: "var(--forge-log-bg)",
              }}
            >
              <SimpleDiffEditor
                original={diffData.original}
                modified={diffData.modified}
                language="json"
                options={{
                  minimap: { enabled: false },
                  fontSize: 13,
                  padding: { top: 4 },
                }}
              />
            </div>
          </div>
        )}
      </div>
    </div>
  );
}
