"use client";

import { Component, memo, type ReactNode } from "react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { MermaidDiagram } from "@/components/markdown/MermaidDiagram";
import { requestCodeNavigation } from "@/lib/workbench-navigation";
import type {
  WikiCodeReference,
  WikiManifest,
  WikiPage as WikiPageModel,
  WikiSection,
} from "@optage/sdk/client";

interface WikiPageProps {
  repositoryId: string;
  manifest: WikiManifest;
  page: WikiPageModel | null;
  loading: boolean;
  error: string | null;
  onSelectPage: (pageId: string) => void;
}

class MarkdownErrorBoundary extends Component<
  { fallback: ReactNode; children: ReactNode },
  { hasError: boolean }
> {
  state = { hasError: false };

  static getDerivedStateFromError() {
    return { hasError: true };
  }

  componentDidCatch(err: unknown) {
    console.error("[wiki.render.error]", err);
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback;
    }
    return this.props.children;
  }
}

function parseCodeLink(href: string) {
  const url = new URL(href, "https://repopilot.local");
  if (url.pathname !== "/__code__" && url.pathname !== "/code") {
    return null;
  }

  const path = url.searchParams.get("path");
  if (!path) {
    return null;
  }

  const line = Number.parseInt(url.searchParams.get("line") || "", 10);
  const endLine = Number.parseInt(url.searchParams.get("end") || "", 10);
  const symbol = url.searchParams.get("symbol") || undefined;

  return {
    path,
    line: Number.isFinite(line) ? line : undefined,
    endLine: Number.isFinite(endLine) ? endLine : undefined,
    symbol,
  };
}

function openCodeReference(
  repositoryId: string,
  target: {
    path: string;
    line?: number;
    endLine?: number;
    symbol?: string;
  },
) {
  requestCodeNavigation({
    repositoryId,
    path: target.path,
    line: target.line,
    endLine: target.endLine,
    symbol: target.symbol,
  });
}

function resolveWikiPageId(href: string, manifest: WikiManifest): string | null {
  if (!href.endsWith(".md")) {
    return null;
  }
  const normalized = href.replace(/^\/+/, "");
  const direct = manifest.pages.find((page) => page.markdownPath === normalized);
  if (direct) {
    return direct.id;
  }
  const fallback = manifest.pages.find((page) => page.markdownPath?.endsWith(normalized));
  return fallback?.id || null;
}

function autoLinkWikiCodeReferences(markdown: string): string {
  return markdown.replace(
    /(?:Source:\s+)?(\/(?:__code__|code)\?[^\s)]+)/g,
    (match, href: string) => {
      const label = match.startsWith("Source:") ? "Source: [open code]" : "[open code]";
      return `${label}(${href})`;
    },
  );
}

/** Strip leading H1 heading (and optional blank lines after it) from markdown
 *  since the page already renders the title from metadata. */
function stripLeadingH1(md: string): string {
  return md.replace(/^\s*#\s+[^\n]+\n*/, "");
}

const MarkdownContent = memo(function MarkdownContent({
  repositoryId,
  manifest,
  markdown,
  onSelectPage,
}: {
  repositoryId: string;
  manifest: WikiManifest;
  markdown: string;
  onSelectPage: (pageId: string) => void;
}) {
  return (
    <MarkdownErrorBoundary
      fallback={
        <pre className="whitespace-pre-wrap break-words text-rp-text font-sans leading-relaxed">
          {markdown}
        </pre>
      }
    >
      <ReactMarkdown
        remarkPlugins={[remarkGfm]}
        components={{
          code({ className, children, ...props }) {
            const match = /language-(\w+)/.exec(className || "");
            const lang = match?.[1];
            const codeText = String(children).replace(/\n$/, "");
            if (lang === "mermaid") {
              return <MermaidDiagram chart={codeText} />;
            }
            if (lang) {
              return (
                <div className="relative group">
                  <div className="absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity">
                    <button
                      onClick={() => navigator.clipboard.writeText(codeText)}
                      className="px-2 py-1 text-r-xs bg-rp-surface text-rp-muted rounded hover:text-rp-text transition-colors"
                    >
                      Copy
                    </button>
                  </div>
                  <pre>
                    <code className={className} {...props}>{children}</code>
                  </pre>
                </div>
              );
            }
            return (
              <code {...props}>
                {children}
              </code>
            );
          },
          table({ children }) {
            return <div className="overflow-x-auto"><table className="w-full">{children}</table></div>;
          },
          a({ href, children }) {
            const safeHref = href || "";
            const codeTarget = parseCodeLink(safeHref);
            const wikiPageId = resolveWikiPageId(safeHref, manifest);

            if (codeTarget) {
              return (
                <button
                  type="button"
                  onClick={() => openCodeReference(repositoryId, codeTarget)}
                  className="inline cursor-pointer break-all text-left font-mono text-r-sm underline decoration-rp-muted/30 underline-offset-2 hover:decoration-rp-muted/70 transition-colors"
                  title={`${codeTarget.path}${codeTarget.line ? `:${codeTarget.line}` : ""}`}
                >
                  {children}
                </button>
              );
            }

            if (wikiPageId) {
              return (
                <button
                  type="button"
                  onClick={() => onSelectPage(wikiPageId)}
                  className="underline decoration-rp-muted/30 underline-offset-2 hover:decoration-rp-muted/70 transition-colors"
                >
                  {children}
                </button>
              );
            }

            return (
              <a
                href={safeHref}
                target={safeHref.startsWith("http") ? "_blank" : undefined}
                rel={safeHref.startsWith("http") ? "noreferrer" : undefined}
              >
                {children}
              </a>
            );
          },
        }}
      >
        {autoLinkWikiCodeReferences(stripLeadingH1(markdown))}
      </ReactMarkdown>
    </MarkdownErrorBoundary>
  );
});

function ReferenceButton({
  repositoryId,
  reference,
}: {
  repositoryId: string;
  reference: WikiCodeReference;
}) {
  const suffix = reference.line ? `:${reference.line}` : "";
  const location = `${reference.path}${suffix}`;
  return (
    <button
      type="button"
      onClick={() => openCodeReference(repositoryId, reference)}
      className="inline text-left text-r-sm underline decoration-rp-muted/30 underline-offset-2 hover:decoration-rp-muted/70 transition-colors"
    >
      <span className="font-medium">{reference.label}</span>
      <span className="ml-2 break-all font-mono text-r-xs text-rp-muted">{location}</span>
    </button>
  );
}

const WikiSectionCard = memo(function WikiSectionCard({
  repositoryId,
  manifest,
  section,
  pageTitle,
  onSelectPage,
}: {
  repositoryId: string;
  manifest: WikiManifest;
  section: WikiSection;
  pageTitle: string;
  onSelectPage: (pageId: string) => void;
}) {
  const relatedPages = section.relatedPageIds
    ?.map((pageId) => manifest.pages.find((page) => page.id === pageId))
    .filter((page): page is NonNullable<typeof page> => page !== undefined);

  const hideTitle = section.title === pageTitle;

  return (
    <section id={section.id} className="scroll-mt-6">
      {!hideTitle && <h2>{section.title}</h2>}
      <div>
        {section.type === "markdown" && section.markdown && (
          <div className="notion-prose wiki-content">
            <MarkdownContent
              repositoryId={repositoryId}
              manifest={manifest}
              markdown={section.markdown}
              onSelectPage={onSelectPage}
            />
          </div>
        )}
        {section.type === "facts" && (
          <ul>
            {(section.items || []).map((item) => (
              <li key={item}>{item}</li>
            ))}
          </ul>
        )}
        {section.type === "references" && (
          <div className="space-y-1">
            {(section.references || []).map((reference) => (
              <div key={`${reference.path}:${reference.line || 0}:${reference.label}`}>
                <ReferenceButton
                  repositoryId={repositoryId}
                  reference={reference}
                />
              </div>
            ))}
          </div>
        )}
        {section.type === "navigation" && (
          <ul>
            {(relatedPages || []).map((page) => (
              <li key={page.id}>
                <button
                  type="button"
                  onClick={() => onSelectPage(page.id)}
                  className="underline decoration-rp-muted/30 underline-offset-3 hover:decoration-rp-muted/70 transition-colors"
                >
                  {page.title}
                </button>
                {page.summary ? <span className="ml-2 text-r-xs text-rp-faint">{page.summary}</span> : null}
              </li>
            ))}
          </ul>
        )}
        {section.type === "diagram" && section.diagram && (
          <MermaidDiagram chart={section.diagram.mermaid} />
        )}
      </div>
    </section>
  );
});

export function WikiPage({
  repositoryId,
  manifest,
  page,
  loading,
  error,
  onSelectPage,
}: WikiPageProps) {
  if (loading) {
    return <div className="flex items-center justify-center h-full px-4 text-rp-muted text-r-sm">Loading page...</div>;
  }
  if (error) {
    return <div className="flex items-center justify-center h-full px-4 text-rp-error text-r-sm text-center">{error}</div>;
  }
  if (!page) {
    return <div className="flex items-center justify-center h-full px-4 text-rp-muted text-r-sm">Select a wiki page from the tree</div>;
  }

  return (
    <div className="flex-1 overflow-y-auto bg-rp-bg">
      <div className="mx-auto w-full max-w-wiki px-6 py-10 sm:px-12 md:px-16 lg:px-24 notion-prose">
        <h1 className="!mt-0 !mb-2 !text-[clamp(2rem,5vw,2.5rem)] !font-bold !tracking-tight !leading-[1.15] text-rp-text-strong">
          {page.displayTitle || page.title}
        </h1>

        {(page.kind || page.componentType || page.domain) ? (
          <p className="text-r-sm text-rp-faint !mb-1">
            {[page.kind || page.pageType, page.componentType, page.domain].filter(Boolean).join(" · ")}
          </p>
        ) : null}

        {(page.displaySummary || page.summary) ? (
          <p className="text-rp-muted !mb-6">
            {page.displaySummary || page.summary}
          </p>
        ) : null}

        {page.generationWarnings?.length ? (
          <div className="text-r-sm text-rp-warning mb-4">
            {page.generationWarnings.map((warning) => (
              <p key={warning}>{warning}</p>
            ))}
          </div>
        ) : null}

        {page.sections.map((section) => (
          <WikiSectionCard
            key={section.id}
            repositoryId={repositoryId}
            manifest={manifest}
            section={section}
            pageTitle={page.displayTitle || page.title}
            onSelectPage={onSelectPage}
          />
        ))}

        {page.readNext?.length ? (
          <div className="mt-12 pt-6 border-t border-rp-border/10">
            <p className="text-r-2xs font-medium text-rp-faint tracking-widest uppercase mb-3">
              Read Next
            </p>
            <div className="space-y-1">
              {page.readNext
                .map((pageId) => manifest.pages.find((c) => c.id === pageId))
                .filter((c): c is NonNullable<typeof c> => c !== undefined)
                .slice(0, 6)
                .map((c) => (
                  <button
                    key={c.id}
                    type="button"
                    onClick={() => onSelectPage(c.id)}
                    className="block text-r-base text-rp-muted hover:text-rp-text transition-colors"
                  >
                    <span className="mr-2 text-rp-faint">→</span>
                    {c.displayTitle || c.title}
                  </button>
                ))}
            </div>
          </div>
        ) : null}
      </div>
    </div>
  );
}

