import {
  Component,
  createContext,
  useContext,
  createEffect,
  createMemo,
  createSignal,
} from "solid-js";
import { useLocation } from "@solidjs/router";
import { useJournalStream } from "./components/stores/journalStream";

// 导入组件以注册自定义元素
import "./components";
import {
  Article,
  MobileSidebar,
  DesktopSidebar,
  DocDialog,
  DataSourceDialog,
  RevealManager,
  ReactiveStatManager,
} from "./components";
import { generateToc, type FileNode, type TocNode } from "./data-loader";
import { JournalPanel } from "./components/journal";

// ---------------------------------------------------------------------------
// Scroll container context – lets child components (FileTree, RevealManager)
// find the correct scrollable element instead of relying on window.scroll
// ---------------------------------------------------------------------------

const ScrollContainerCtx = createContext<() => HTMLElement | undefined>();

/** Access the main content scroll container from any descendant. */
export function useScrollContainer(): () => HTMLElement | undefined {
  const ctx = useContext(ScrollContainerCtx);
  return ctx ?? (() => undefined);
}

// ---------------------------------------------------------------------------
// App
// ---------------------------------------------------------------------------

const App: Component = () => {
  const location = useLocation();
  const stream = useJournalStream();
  const [isSidebarOpen, setIsSidebarOpen] = createSignal(false);
  const [isDocOpen, setIsDocOpen] = createSignal(false);
  const [isDataSourceOpen, setIsDataSourceOpen] = createSignal(false);
  const [isJournalOpen, setIsJournalOpen] = createSignal(false);

  // Sidebar and TOC data — reload when source changes
  const [fileTree, setFileTree] = createSignal<FileNode[]>([]);
  const [pathHeadings, setPathHeadings] = createSignal<
    Record<string, TocNode[]>
  >({});
  const [tocKey, setTocKey] = createSignal(0);

  let mainRef!: HTMLElement;

  const loadToc = async () => {
    const toc = await generateToc();
    setFileTree(toc.fileTree);
    setPathHeadings(toc.pathHeadings);
  };

  // Load TOC on mount and when source changes
  createEffect(() => {
    void tocKey();
    void loadToc();
  });

  const handleSourceChanged = () => {
    setTocKey((k) => k + 1);
  };

  const currentPath = createMemo(() => {
    // 根据路由加载对应的 markdown 文件
    let path = decodeURIComponent(location.pathname);

    if (!path) path = "/content/";
    if (path.endsWith("/")) path += "index";
    if (!path.endsWith(".md")) path += ".md";

    return path;
  });

  return (
    <div class="h-screen flex flex-col overflow-hidden bg-gray-50">
      {/* Header */}
      <header class="shrink-0 h-16 bg-white shadow z-30">
        <div class="h-full max-w-4xl mx-auto px-4 flex items-center gap-4">
          {/* 仅在移动端显示菜单按钮 */}
          <button
            onClick={() => setIsSidebarOpen(true)}
            class="md:hidden text-gray-600 hover:text-gray-900 p-1 rounded hover:bg-gray-100"
            title="目录"
          >
            ☰
          </button>
          <h1 class="text-2xl font-bold text-gray-900">Tabletop Toolkit</h1>
          <div class="flex-1" />
          <button
            onClick={() => setIsJournalOpen((v) => !v)}
            class={`relative w-8 h-8 rounded flex items-center justify-center text-sm ${
              isJournalOpen()
                ? "bg-blue-100 text-blue-600"
                : "text-gray-500 hover:bg-gray-100"
            }`}
            title={`Journal (${stream.connectionStatus})`}
          >
            <span
              class="absolute top-0.5 right-0.5 w-2 h-2 rounded-full border border-white"
              classList={{
                "bg-gray-400": stream.connectionStatus === "disconnected",
                "bg-yellow-400 animate-pulse":
                  stream.connectionStatus === "connecting",
                "bg-green-500": stream.connectionStatus === "connected",
                "bg-red-500": stream.connectionStatus === "error",
              }}
            />
            📋
          </button>
          <button
            onClick={() => setIsDocOpen(true)}
            class="w-8 h-8 rounded-full border border-gray-300 text-gray-500 hover:text-gray-700 hover:border-gray-400 flex items-center justify-center text-sm font-medium"
            title="指令文档"
          >
            ?
          </button>
        </div>
      </header>

      {/* 移动端抽屉式侧边栏 (overlay) */}
      <MobileSidebar
        isOpen={isSidebarOpen()}
        onClose={() => setIsSidebarOpen(false)}
        fileTree={fileTree()}
        pathHeadings={pathHeadings()}
        onDataSourceOpen={() => setIsDataSourceOpen(true)}
      />

      {/* Body: sidebar + main + journal */}
      <div class="flex flex-1 min-h-0">
        {/* 桌面端固定侧边栏 (flex child) */}
        <DesktopSidebar
          fileTree={fileTree()}
          pathHeadings={pathHeadings()}
          onDataSourceOpen={() => setIsDataSourceOpen(true)}
        />

        {/* Main content — the scrollable region */}
        <ScrollContainerCtx.Provider value={() => mainRef}>
          <main ref={mainRef} class="flex-1 min-w-0 overflow-y-auto">
            <div class="max-w-4xl mx-auto px-4 py-8">
              <Article
                class="prose prose-sm max-w-full"
                src={currentPath()}
              >
                <RevealManager />
                <ReactiveStatManager />
              </Article>
            </div>
          </main>
        </ScrollContainerCtx.Provider>

        {/* Journal panel wrapper — on desktop: flex child with width transition;
            on mobile: passes through to JournalPanel's own overlay */}
        <div
          class="contents md:block md:shrink-0 md:overflow-hidden md:transition-all md:duration-300"
          classList={{
            "md:w-105": isJournalOpen(),
            "md:w-0": !isJournalOpen(),
          }}
        >
          <JournalPanel
            open={isJournalOpen()}
            onClose={() => setIsJournalOpen(false)}
          />
        </div>
      </div>

      <DocDialog isOpen={isDocOpen()} onClose={() => setIsDocOpen(false)} />
      <DataSourceDialog
        isOpen={isDataSourceOpen()}
        onClose={() => setIsDataSourceOpen(false)}
        onSourceChanged={handleSourceChanged}
      />
    </div>
  );
};

export default App;
