import { useState, useEffect, useCallback, createContext, useContext, lazy, Suspense } from "react";
import { Routes, Route, useNavigate, useParams } from "react-router-dom";
import { Sidebar } from "./components/Sidebar";
import { Editor } from "./components/Editor";
import { Backlinks } from "./components/Backlinks";
import { GraphView } from "./components/GraphView";
import { CommandPalette } from "./components/CommandPalette";
import { SplitView } from "./components/SplitView";
import { LinkPreview } from "./components/LinkPreview";
import { CalendarView } from "./components/CalendarView";
import { ThemePicker, useThemeInit } from "./components/ThemePicker";
import { KanbanView } from "./components/KanbanView";
import { SearchReplace } from "./components/SearchReplace";
import { FlashcardView } from "./components/FlashcardView";
import { CSSEditor, useCustomCssInit } from "./components/CSSEditor";
import { TabBar } from "./components/TabBar";
const WhiteboardView = lazy(() => import("./components/WhiteboardView").then(m => ({ default: m.WhiteboardView })));
import { DatabaseView } from "./components/DatabaseView";
import { GitPanel } from "./components/GitPanel";
import { TimelineView } from "./components/TimelineView";
import { GraphAnalytics } from "./components/GraphAnalytics";
import IntegrityReport from "./components/IntegrityReport";
import AuditLog from "./components/AuditLog";
import {
  listNotes,
  readNote,
  writeNote,
  getVaultPath,
  setVaultPath,
  ensureVault,
  getOrCreateDaily,
  addVault,
  getFavorites,
  getBacklinkContext,
  setFavorites as setFavoritesCmd,
  type NoteEntry,
} from "./lib/commands";
import { extractWikilinks, type BacklinkEntry } from "./lib/wikilinks";

/* ── Vault Context ──────────────────────────────────────────── */
interface VaultContextType {
  vaultPath: string;
  notes: NoteEntry[];
  refreshNotes: () => Promise<void>;
  currentNote: string | null;
  setCurrentNote: (path: string | null) => void;
  noteContent: string;
  setNoteContent: (content: string) => void;
  backlinks: BacklinkEntry[];
  navigateToNote: (name: string) => void;
  sidebarOpen: boolean;
  toggleSidebar: () => void;
  editMode: boolean;
  toggleEditMode: () => void;
  splitNote: string | null;
  setSplitNote: (path: string | null) => void;
  favorites: string[];
  toggleFavorite: (path: string) => void;
  recentNotes: string[];
  switchVault: (path: string) => Promise<void>;
  focusMode: boolean;
  toggleFocusMode: () => void;
}

const VaultContext = createContext<VaultContextType>(null!);
export const useVault = () => useContext(VaultContext);

/* ── Main App ───────────────────────────────────────────────── */
export default function App() {
  const [vaultPath, setVaultPathState] = useState<string>("");
  const [notes, setNotes] = useState<NoteEntry[]>([]);
  const [currentNote, setCurrentNote] = useState<string | null>(null);
  const [noteContent, setNoteContent] = useState<string>("");
  const [backlinks, setBacklinks] = useState<BacklinkEntry[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [sidebarOpen, setSidebarOpen] = useState(true);
  const [editMode, setEditMode] = useState(true);
  const [cmdPaletteOpen, setCmdPaletteOpen] = useState(false);
  const [splitNote, setSplitNote] = useState<string | null>(null);
  const [favorites, setFavorites] = useState<string[]>([]);
  const [recentNotes, setRecentNotes] = useState<string[]>([]);
  const [themePickerOpen, setThemePickerOpen] = useState(false);
  const [focusMode, setFocusMode] = useState(false);
  const [searchReplaceOpen, setSearchReplaceOpen] = useState(false);
  const [cssEditorOpen, setCssEditorOpen] = useState(false);
  const navigate = useNavigate();

  // Apply saved theme + custom CSS on mount
  useThemeInit();
  useCustomCssInit();

  const toggleSidebar = useCallback(() => setSidebarOpen(v => !v), []);
  const toggleEditMode = useCallback(() => setEditMode(v => !v), []);
  const toggleFocusMode = useCallback(() => setFocusMode(v => !v), []);


  // Initialize vault
  useEffect(() => {
    (async () => {
      try {
        console.log("[GraphNotes] Initializing vault...");
        let path: string | null = null;

        try {
          path = await getVaultPath();
          console.log("[GraphNotes] Stored vault path:", path);
        } catch (e) {
          console.warn("[GraphNotes] getVaultPath failed:", e);
        }

        if (!path) {
          // No stored vault path — use a sensible default
          path = "./vault";
          console.log("[GraphNotes] Using default vault path:", path);
          try {
            await setVaultPath(path);
          } catch (e) {
            console.warn("[GraphNotes] setVaultPath failed:", e);
          }
        }

        try {
          await ensureVault(path);
        } catch (e) {
          console.warn("[GraphNotes] ensureVault failed:", e);
        }

        setVaultPathState(path);
        console.log("[GraphNotes] Vault ready at:", path);
        setLoading(false);
      } catch (e) {
        console.error("[GraphNotes] Init failed:", e);
        setError(String(e));
        setLoading(false);
      }
    })();
  }, []);

  // Load notes when vault is ready
  const refreshNotes = useCallback(async () => {
    if (!vaultPath) return;
    const entries = await listNotes(vaultPath);
    setNotes(entries);
  }, [vaultPath]);

  useEffect(() => {
    if (vaultPath) refreshNotes();
    // Load favorites
    if (vaultPath) {
      getFavorites(vaultPath).then(setFavorites).catch(() => setFavorites([]));
    }
  }, [vaultPath, refreshNotes]);

  // Track recent notes
  const trackRecent = useCallback((notePath: string) => {
    setRecentNotes(prev => {
      const next = [notePath, ...prev.filter(p => p !== notePath)].slice(0, 10);
      return next;
    });
  }, []);

  // Watch currentNote changes to track recents
  useEffect(() => {
    if (currentNote) trackRecent(currentNote);
  }, [currentNote, trackRecent]);

  // Toggle favorite
  const toggleFavorite = useCallback((path: string) => {
    setFavorites(prev => {
      const next = prev.includes(path)
        ? prev.filter(p => p !== path)
        : [...prev, path];
      // Persist
      if (vaultPath) setFavoritesCmd(vaultPath, next).catch(() => { });
      return next;
    });
  }, [vaultPath]);

  // Switch vault
  const switchVault = useCallback(async (newPath: string) => {
    try {
      await ensureVault(newPath);
      await setVaultPath(newPath);
      await addVault(newPath);
      setVaultPathState(newPath);
      setCurrentNote(null);
      setNoteContent("");
      setSplitNote(null);
      setRecentNotes([]);
      navigate("/");
    } catch (e) {
      console.error("Switch vault failed:", e);
    }
  }, [navigate, setCurrentNote, setNoteContent]);

  // Build backlinks for current note using backend context
  useEffect(() => {
    if (!vaultPath || !currentNote || !notes.length) {
      setBacklinks([]);
      return;
    }

    (async () => {
      const currentName = currentNote
        .replace(/\.md$/, "")
        .split("/")
        .pop() || "";
      if (!currentName) return;

      try {
        const contexts = await getBacklinkContext(vaultPath, currentName);
        const entries: BacklinkEntry[] = contexts.map(c => ({
          sourcePath: c.source_path,
          sourceName: c.source_name,
          context: c.excerpt,
        }));
        setBacklinks(entries);
      } catch {
        // Fallback: simple wikilink scan
        const allPaths = flattenNotes(notes);
        const entries: BacklinkEntry[] = [];
        for (const notePath of allPaths) {
          if (notePath === currentNote) continue;
          try {
            const content = await readNote(vaultPath, notePath);
            const links = extractWikilinks(content);
            for (const link of links) {
              if (link.target.toLowerCase() === currentName.toLowerCase()) {
                const lines = content.split("\n");
                const contextLine = lines.find((l) => l.includes(link.raw)) || "";
                entries.push({
                  sourcePath: notePath,
                  sourceName: notePath.replace(/\.md$/, "").split("/").pop() || notePath,
                  context: contextLine.trim().substring(0, 200),
                });
              }
            }
          } catch { }
        }
        setBacklinks(entries);
      }
    })();
  }, [vaultPath, currentNote, notes]);

  const navigateToNote = useCallback(
    (name: string) => {
      // Find the note by name (case-insensitive)
      const allPaths = flattenNotes(notes);
      const match = allPaths.find(
        (p) =>
          p
            .replace(/\.md$/, "")
            .split("/")
            .pop()
            ?.toLowerCase() === name.toLowerCase()
      );
      if (match) {
        navigate(`/note/${encodeURIComponent(match)}`);
      } else {
        // Create new note
        const newPath = `${name}.md`;
        writeNote(vaultPath, newPath, `# ${name}\n\n`).then(() => {
          refreshNotes();
          navigate(`/note/${encodeURIComponent(newPath)}`);
        });
      }
    },
    [notes, vaultPath, navigate, refreshNotes]
  );

  // ── Global keyboard shortcuts ──
  useEffect(() => {
    const handler = (e: KeyboardEvent) => {
      const mod = e.metaKey || e.ctrlKey;
      if (!mod) return;

      // ⌘⇧F — Focus mode
      if (e.shiftKey && e.key.toLowerCase() === "f") {
        e.preventDefault();
        setFocusMode(v => !v);
        return;
      }

      switch (e.key.toLowerCase()) {
        case "k":
          e.preventDefault();
          setCmdPaletteOpen(v => !v);
          break;
        case "n":
          e.preventDefault();
          {
            const name = prompt("Note name:");
            if (name?.trim()) navigateToNote(name.trim());
          }
          break;
        case "g":
          e.preventDefault();
          navigate("/graph");
          break;
        case "d":
          e.preventDefault();
          navigate("/daily");
          break;
        case "e":
          e.preventDefault();
          toggleEditMode();
          break;
        case "\\":
          e.preventDefault();
          toggleSidebar();
          break;
        case "t":
          e.preventDefault();
          setThemePickerOpen(v => !v);
          break;
        case "h":
          e.preventDefault();
          setSearchReplaceOpen(v => !v);
          break;
        case "u":
          e.preventDefault();
          setCssEditorOpen(v => !v);
          break;
      }
    };
    window.addEventListener("keydown", handler);
    return () => window.removeEventListener("keydown", handler);
  }, [navigate, navigateToNote, toggleEditMode, toggleSidebar]);

  if (loading) {
    return (
      <div className="flex items-center justify-center h-screen">
        <div className="text-center animate-fade-in">
          <div className="text-4xl mb-4">📝</div>
          <p className="text-[var(--text-secondary)]">Loading vault...</p>
        </div>
      </div>
    );
  }

  if (error) {
    return (
      <div className="flex items-center justify-center h-screen">
        <div className="text-center animate-fade-in max-w-md">
          <div className="text-4xl mb-4">⚠️</div>
          <p className="text-[var(--text-primary)] font-semibold mb-2">Failed to load vault</p>
          <p className="text-[var(--text-muted)] text-sm">{error}</p>
        </div>
      </div>
    );
  }

  return (
    <VaultContext.Provider
      value={{
        vaultPath,
        notes,
        refreshNotes,
        currentNote,
        setCurrentNote,
        noteContent,
        setNoteContent,
        backlinks,
        navigateToNote,
        sidebarOpen,
        toggleSidebar,
        editMode,
        toggleEditMode,
        splitNote,
        setSplitNote,
        favorites,
        toggleFavorite,
        recentNotes,
        switchVault,
        focusMode,
        toggleFocusMode,
      }}
    >
      <div className={`flex h-screen w-screen overflow-hidden ${focusMode ? "focus-mode" : ""}`}>
        {sidebarOpen && !focusMode && <Sidebar />}
        <Routes>
          <Route path="/" element={<WelcomeScreen />} />
          <Route path="/note/:path" element={<SplitView />} />
          <Route path="/daily" element={<DailyView />} />
          <Route path="/graph" element={<GraphView />} />
          <Route path="/calendar" element={<CalendarView />} />
          <Route path="/kanban" element={<KanbanView />} />
          <Route path="/flashcards" element={<FlashcardView />} />
          <Route path="/whiteboard/:name" element={<Suspense fallback={<div className="flex-1 flex items-center justify-center"><p className="text-[var(--text-muted)]">Loading whiteboard...</p></div>}><WhiteboardView /></Suspense>} />
          <Route path="/database" element={<DatabaseView />} />
          <Route path="/timeline" element={<TimelineView />} />
          <Route path="/analytics" element={<GraphAnalytics />} />
          <Route path="/integrity" element={<IntegrityReport onClose={() => navigate('/')} />} />
          <Route path="/audit-log" element={<AuditLog onClose={() => navigate('/')} />} />
        </Routes>
      </div>
      <CommandPalette open={cmdPaletteOpen} onClose={() => setCmdPaletteOpen(false)} />
      <LinkPreview />
      <ThemePicker open={themePickerOpen} onClose={() => setThemePickerOpen(false)} />
      <SearchReplace open={searchReplaceOpen} onClose={() => setSearchReplaceOpen(false)} />
      <CSSEditor open={cssEditorOpen} onClose={() => setCssEditorOpen(false)} />
    </VaultContext.Provider>
  );
}


/* ── Daily View ─────────────────────────────────────────────── */
function DailyView() {
  const { vaultPath, refreshNotes } = useVault();
  const navigate = useNavigate();

  useEffect(() => {
    if (!vaultPath) return;
    getOrCreateDaily(vaultPath).then((dailyPath) => {
      refreshNotes();
      navigate(`/note/${encodeURIComponent(dailyPath)}`, { replace: true });
    }).catch((e) => {
      console.error("[GraphNotes] Failed to create daily note:", e);
      navigate("/", { replace: true });
    });
  }, [vaultPath, navigate, refreshNotes]);

  return (
    <div className="flex-1 flex items-center justify-center">
      <p className="text-[var(--text-muted)]">Creating daily note...</p>
    </div>
  );
}

/* ── Welcome Screen ─────────────────────────────────────────── */
function WelcomeScreen() {
  const navigate = useNavigate();

  return (
    <div className="welcome">
      <div className="welcome-card">
        <div className="welcome-icon">📝</div>
        <h1 className="welcome-title">Graph Notes</h1>
        <p className="welcome-subtitle">
          A local-first knowledge base with bidirectional linking
          and graph visualization. Your notes, your data.
        </p>
        <div className="welcome-actions">
          <button className="btn btn-primary" onClick={() => navigate("/daily")}>
            📅 Today's Note
          </button>
          <button className="btn" onClick={() => navigate("/graph")}>
            🔮 Graph View
          </button>
        </div>
      </div>
    </div>
  );
}

/* ── Helpers ────────────────────────────────────────────────── */
function flattenNotes(entries: NoteEntry[]): string[] {
  const paths: string[] = [];
  for (const entry of entries) {
    if (entry.is_dir && entry.children) {
      paths.push(...flattenNotes(entry.children));
    } else if (!entry.is_dir) {
      paths.push(entry.path);
    }
  }
  return paths;
}
