import {
  Component,
  ParentProps,
  createContext,
  useContext,
  createEffect,
  onCleanup,
  Show,
  createResource,
  createSignal,
} from "solid-js";
import { parseMarkdown } from "../markdown";
import { extractSection } from "../data-loader";
import mermaid from "mermaid";
import { getIndexedData } from "../data-loader/file-index";
import { useNavigateWithParams } from "./useNavigateWithParams";

export interface ArticleProps {
  src: string;
  section?: string; // 指定要显示的标题（不含 #）
  onLoaded?: () => void;
  onError?: (error: Error) => void;
  class?: string; // 额外的 class 用于样式控制
  scrollToHash?: boolean; // 是否自动滚动到 hash
}

// ---------------------------------------------------------------------------
// Article DOM context – lets child components react to the content container
// ---------------------------------------------------------------------------

const ArticleDomCtx = createContext<() => HTMLDivElement | undefined>();

/** Access the article's content DOM element from a child component. */
export function useArticleDom(): () => HTMLDivElement | undefined {
  const ctx = useContext(ArticleDomCtx);
  if (!ctx) throw new Error("useArticleDom must be used inside an <Article>");
  return ctx;
}

async function fetchArticleContent(params: {
  src: string;
  section?: string;
}): Promise<string> {
  const text = await getIndexedData(params.src);
  // 如果指定了 section，提取对应内容
  return params.section ? extractSection(text, params.section) : text;
}

/**
 * 滚动到指定的 hash 元素
 */
function scrollToHash(hash: string) {
  if (!hash) return;
  // 移除 # 前缀
  const id = hash.startsWith("#") ? hash.slice(1) : hash;
  if (!id) return;

  // 使用 decodeURIComponent 解码 ID（处理中文等特殊字符）
  const decodedId = decodeURIComponent(id);

  // 尝试查找元素
  const element = document.getElementById(decodedId);
  if (element) {
    // 使用 scrollIntoView 滚动到元素
    element.scrollIntoView({ behavior: "instant", block: "start" });
    return true;
  }
  return false;
}

/**
 * Article 组件
 * 用于将特定 src 位置的 md 文件显示为 markdown 文章
 */
export const Article: Component<ArticleProps & ParentProps> = (props) => {
  const navigate = useNavigateWithParams();
  const [content, { refetch }] = createResource(
    () => ({ src: props.src, section: props.section }),
    fetchArticleContent,
  );
  const [contentDom, setContentDom] = createSignal<HTMLDivElement>();

  createEffect(() => {
    const data = content();
    if (data) {
      props.onLoaded?.();
      // 内容加载完成后，渲染 mermaid 图表
      void mermaid.run();

      // 内容渲染后检查 hash 并滚动
      scrollToHash(window.location.hash);
    }
  });

  // Intercept markdown <a> links to use client-side navigation with
  // preserved URL search params.
  createEffect(() => {
    const dom = contentDom();
    if (!dom) return;

    const onClick = (e: MouseEvent) => {
      const anchor = (e.target as HTMLElement).closest("a[href]");
      if (!anchor) return;
      const href = anchor.getAttribute("href");
      if (!href) return;
      // Only intercept same-origin navigation links (not external, not anchors)
      if (href.startsWith("http") || href.startsWith("//")) return;
      if (href.startsWith("#")) return;

      e.preventDefault();
      // Resolve relative hrefs against the current page path so that
      // e.g. "blah.md" on /content/page.md becomes /content/blah
      const resolved = new URL(href, window.location.origin + window.location.pathname);
      let pathname = resolved.pathname;
      // Strip .md extension so refreshes hit the SPA fallback, not the raw file
      if (pathname.endsWith(".md")) {
        pathname = pathname.slice(0, -3);
      }
      navigate(pathname + resolved.hash);
    };

    dom.addEventListener("click", onClick);
    onCleanup(() => dom.removeEventListener("click", onClick));
  });

  onCleanup(() => {
    // 清理时清空内容，触发内部组件的销毁
  });

  return (
    <article
      class={`prose ${props.class || ""}`}
      data-src={props.src}
    >
      <Show when={content.loading}>
        <div class="text-gray-500">加载中...</div>
      </Show>
      <Show when={content.error}>
        <div class="text-red-500">加载失败：{content.error?.message}</div>
      </Show>
      <Show when={!content.loading && !content.error && content()}>
        <ArticleDomCtx.Provider value={contentDom}>
          <div
            class="relative"
            ref={setContentDom}
            innerHTML={parseMarkdown(content()!, props.src)}
          />
          {props.children}
        </ArticleDomCtx.Provider>
      </Show>
    </article>
  );
};

export default Article;
