import { useState, useEffect, useCallback, useRef } from "react";
import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";
// clipboard write now happens in Rust's paste_and_refocus command
import { getCurrentWindow } from "@tauri-apps/api/window";
import SearchBar from "./components/SearchBar";
import ClipboardList from "./components/ClipboardList";
import SettingsPanel from "./components/SettingsPanel";
import ContextMenu from "./components/ContextMenu";
import type { ClipboardEntry, Settings } from "./types";

export default function App() {
  const [entries, setEntries] = useState<ClipboardEntry[]>([]);
  const [query, setQuery] = useState("");
  const [showSettings, setShowSettings] = useState(false);
  const [settings, setSettings] = useState<Settings | null>(null);
  const [selectedIds, setSelectedIds] = useState<Set<number>>(new Set());
  const [anchorIndex, setAnchorIndex] = useState(0);
  const [focusIndex, setFocusIndex] = useState(0);
  const [contextMenu, setContextMenu] = useState<{
    x: number;
    y: number;
    entry: ClipboardEntry;
  } | null>(null);

  const pollRef = useRef<ReturnType<typeof setInterval>>();
  const resizeTimer = useRef<ReturnType<typeof setTimeout>>();

  const loadEntries = useCallback(async () => {
    try {
      const limit = settings?.max_history ?? 10000;
      const data: ClipboardEntry[] = query.trim()
        ? await invoke("search_entries", { query, limit })
        : await invoke("get_entries", { limit });
      setEntries(data);
    } catch (e) {
      console.error("Failed to load entries:", e);
    }
  }, [query, settings?.max_history]);

  const loadSettings = useCallback(async () => {
    try {
      const s: Settings = await invoke("get_settings");
      setSettings(s);
    } catch (e) {
      console.error("Failed to load settings:", e);
    }
  }, []);

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

  useEffect(() => {
    loadEntries();
    pollRef.current = setInterval(loadEntries, 1000);
    return () => clearInterval(pollRef.current);
  }, [loadEntries]);

  useEffect(() => {
    const unlisten = listen("open-settings", () => setShowSettings(true));
    return () => {
      unlisten.then((fn) => fn());
    };
  }, []);

  // Persist window size on resize (debounced)
  useEffect(() => {
    const handleResize = () => {
      clearTimeout(resizeTimer.current);
      resizeTimer.current = setTimeout(async () => {
        const win = getCurrentWindow();
        const size = await win.innerSize();
        const scaleFactor = await win.scaleFactor();
        const w = Math.round(size.width / scaleFactor);
        const h = Math.round(size.height / scaleFactor);
        invoke("save_window_size", { width: w, height: h });
      }, 500);
    };
    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []);

  // Copy selected entries and paste into previous app
  const pasteEntries = useCallback(
    async (entriesToPaste: ClipboardEntry[]) => {
      if (entriesToPaste.length === 0) return;
      try {
        const content = entriesToPaste
          .map((e) => e.content)
          .join("\n");
        await invoke("paste_and_refocus", { content });
      } catch (e) {
        console.error("Paste failed:", e);
      }
    },
    []
  );

  const pasteSingle = useCallback(
    (entry: ClipboardEntry) => pasteEntries([entry]),
    [pasteEntries]
  );

  const handleDelete = useCallback(
    async (ids: number[]) => {
      for (const id of ids) {
        await invoke("delete_entry", { id });
      }
      setSelectedIds(new Set());
      loadEntries();
    },
    [loadEntries]
  );

  const handleTogglePin = useCallback(
    async (id: number) => {
      await invoke("toggle_pin", { id });
      loadEntries();
    },
    [loadEntries]
  );

  // Selection helpers
  const selectOnly = useCallback((index: number, entries: ClipboardEntry[]) => {
    const e = entries[index];
    if (e) {
      setSelectedIds(new Set([e.id]));
      setAnchorIndex(index);
      setFocusIndex(index);
    }
  }, []);

  const selectRange = useCallback(
    (from: number, to: number, entries: ClipboardEntry[]) => {
      const lo = Math.min(from, to);
      const hi = Math.max(from, to);
      const ids = new Set<number>();
      for (let i = lo; i <= hi; i++) {
        if (entries[i]) ids.add(entries[i].id);
      }
      setSelectedIds(ids);
      setFocusIndex(to);
    },
    []
  );

  const toggleSelect = useCallback(
    (index: number, entries: ClipboardEntry[]) => {
      const e = entries[index];
      if (!e) return;
      setSelectedIds((prev) => {
        const next = new Set(prev);
        if (next.has(e.id)) next.delete(e.id);
        else next.add(e.id);
        return next;
      });
      setAnchorIndex(index);
      setFocusIndex(index);
    },
    []
  );

  // Keyboard navigation
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      // Cmd+1-9 quick paste
      if (e.metaKey && !e.shiftKey && e.key >= "1" && e.key <= "9") {
        e.preventDefault();
        const idx = parseInt(e.key) - 1;
        if (idx < entries.length) pasteSingle(entries[idx]);
        return;
      }

      // Cmd+A select all
      if (e.metaKey && e.key === "a" && document.activeElement?.tagName !== "INPUT") {
        e.preventDefault();
        setSelectedIds(new Set(entries.map((e) => e.id)));
        return;
      }

      if (e.key === "ArrowDown") {
        e.preventDefault();
        const next = Math.min(focusIndex + 1, entries.length - 1);
        if (e.shiftKey) {
          selectRange(anchorIndex, next, entries);
        } else {
          selectOnly(next, entries);
        }
      } else if (e.key === "ArrowUp") {
        e.preventDefault();
        const next = Math.max(focusIndex - 1, 0);
        if (e.shiftKey) {
          selectRange(anchorIndex, next, entries);
        } else {
          selectOnly(next, entries);
        }
      } else if (e.key === "Enter") {
        e.preventDefault();
        const selected = entries.filter((e) => selectedIds.has(e.id));
        if (selected.length > 0) pasteEntries(selected);
        else if (entries[focusIndex]) pasteSingle(entries[focusIndex]);
      } else if (e.key === "Delete" || e.key === "Backspace") {
        if (document.activeElement?.tagName !== "INPUT") {
          e.preventDefault();
          const ids = Array.from(selectedIds);
          if (ids.length > 0) handleDelete(ids);
        }
      } else if (e.key === "Escape") {
        if (showSettings) {
          setShowSettings(false);
        } else if (selectedIds.size > 1) {
          selectOnly(focusIndex, entries);
        } else {
          getCurrentWindow().hide();
        }
      }
    };

    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, [
    entries, focusIndex, anchorIndex, selectedIds, showSettings,
    pasteSingle, pasteEntries, handleDelete, selectOnly, selectRange,
  ]);

  useEffect(() => {
    const close = () => setContextMenu(null);
    window.addEventListener("click", close);
    return () => window.removeEventListener("click", close);
  }, []);

  const selectedCount = selectedIds.size;

  return (
    <div className="flex flex-col h-screen w-screen bg-surface overflow-hidden">
      {/* Titlebar drag region — sits behind the native traffic lights */}
      <div className="titlebar-spacer shrink-0" data-tauri-drag-region />

      {showSettings && settings ? (
        <SettingsPanel
          settings={settings}
          onClose={() => setShowSettings(false)}
          onUpdate={(s) => {
            setSettings(s);
            loadSettings();
          }}
        />
      ) : (
        <>
          <div className="shrink-0 px-2 pb-0" data-tauri-drag-region>
            <SearchBar
              value={query}
              onChange={(v) => {
                setQuery(v);
                setFocusIndex(0);
                setAnchorIndex(0);
                setSelectedIds(new Set());
              }}
            />
          </div>

          <div className="flex-1 overflow-y-auto min-h-0">
            <ClipboardList
              entries={entries}
              selectedIds={selectedIds}
              focusIndex={focusIndex}
              showImages={settings?.show_images ?? true}
              onSelect={(entry) => pasteSingle(entry)}
              onCtrlClick={(index) => toggleSelect(index, entries)}
              onShiftClick={(index) => selectRange(anchorIndex, index, entries)}
              onPlainClick={(index) => selectOnly(index, entries)}
              onContextMenu={(e, entry) => {
                e.preventDefault();
                if (!selectedIds.has(entry.id)) {
                  const idx = entries.findIndex((x) => x.id === entry.id);
                  selectOnly(idx, entries);
                }
                setContextMenu({ x: e.clientX, y: e.clientY, entry });
              }}
              setFocusIndex={setFocusIndex}
            />
          </div>

          <div className="shrink-0 px-3 py-1.5 border-t border-border text-[11px] text-text-secondary flex justify-between items-center">
            <span>
              {selectedCount > 1 ? `${selectedCount} selected` : "⌘1-9 quick paste"}
            </span>
            <span>{entries.length} items</span>
          </div>
        </>
      )}

      {contextMenu && (
        <ContextMenu
          x={contextMenu.x}
          y={contextMenu.y}
          entry={contextMenu.entry}
          selectedCount={selectedCount}
          onCopy={() => {
            const selected = entries.filter((e) => selectedIds.has(e.id));
            pasteEntries(selected.length > 0 ? selected : [contextMenu.entry]);
          }}
          onPin={() => handleTogglePin(contextMenu.entry.id)}
          onDelete={() => {
            const ids = selectedIds.size > 0 ? Array.from(selectedIds) : [contextMenu.entry.id];
            handleDelete(ids);
          }}
        />
      )}
    </div>
  );
}
