"use client";

import { useCallback, useEffect, useId, useRef, useState } from "react";

let initialized = false;

const MIN_SCALE = 0.1;
const MAX_SCALE = 3;
const ZOOM_STEP = 0.1;

/**
 * Client-side Mermaid diagram renderer (Nextra-style).
 *
 * Uses the standard `mermaid` import (dompurify is a regular dependency
 * since mermaid 11.13+). Validates syntax with `parse()` before calling
 * `render()` to surface clear error messages.
 */
export function MermaidDiagram({ chart }: { chart: string }) {
  // React useId gives a stable, SSR-safe identifier; colons are invalid
  // in DOM element IDs so replace them.
  const reactId = useId().replace(/:/g, "_");
  const containerRef = useRef<HTMLDivElement>(null);
  const [svg, setSvg] = useState("");
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    let cancelled = false;

    (async () => {
      try {
        const { default: mermaid } = await import("mermaid");

        if (!initialized) {
          mermaid.initialize({
            startOnLoad: false,
            theme: "dark",
            securityLevel: "loose",
            suppressErrorRendering: true,
            maxTextSize: 200000,
            themeVariables: {
              primaryColor: "#2383e2",
              primaryTextColor: "#e8e8e8",
              primaryBorderColor: "#333333",
              lineColor: "#888888",
              secondaryColor: "#252525",
              tertiaryColor: "#1e1e1e",
              fontFamily: "ui-monospace, monospace",
              fontSize: "13px",
              background: "#191919",
              mainBkg: "#252525",
              nodeBorder: "#333333",
              clusterBkg: "#1e1e1e",
              titleColor: "#e8e8e8",
              edgeLabelBackground: "#252525",
            },
            flowchart: { htmlLabels: true, curve: "basis" },
          });
          initialized = true;
        }

        const source = chart.trim();

        // Validate syntax first — parse() gives a clear error message
        // without attempting a full DOM render.
        await mermaid.parse(source);

        const id = `mermaid${reactId}${Date.now()}`;

        // Create an off-screen container for mermaid to measure text and
        // build the SVG. Required to avoid "firstChild is null" errors.
        const tempEl = document.createElement("div");
        tempEl.id = `d${id}`;
        tempEl.style.cssText = "position:absolute;left:-9999px;top:-9999px";
        document.body.appendChild(tempEl);

        let renderedSvg: string;
        try {
          const result = await mermaid.render(id, source, tempEl);
          renderedSvg = result.svg;
        } finally {
          tempEl.remove();
        }

        if (!cancelled) {
          setSvg(renderedSvg);
          setError(null);
        }
      } catch (err) {
        if (!cancelled) {
          // Clean up any orphaned temp containers mermaid may have left
          document.querySelectorAll('[id^="dmermaid"]').forEach((el) => el.remove());
          const message = err instanceof Error ? err.message : String(err);
          console.error("[Mermaid] render failed:", message);
          setError(message);
        }
      }
    })();

    return () => {
      cancelled = true;
    };
  }, [chart, reactId]);

  if (error) {
    return (
      <div className="my-4 bg-rp-surface rounded-lg p-6">
        <p className="text-rp-error text-r-xs mb-2">Diagram error</p>
        <p className="text-r-xs text-rp-muted mb-3 italic">{error}</p>
        <details className="text-r-xs text-rp-muted">
          <summary className="cursor-pointer hover:text-rp-text">Show source</summary>
          <pre className="mt-2 font-mono whitespace-pre-wrap overflow-x-auto">{chart}</pre>
        </details>
      </div>
    );
  }

  const [scale, setScale] = useState(1);
  const [translate, setTranslate] = useState({ x: 0, y: 0 });
  const dragRef = useRef<{ startX: number; startY: number; origX: number; origY: number } | null>(null);

  const handleWheel = useCallback((e: React.WheelEvent) => {
    e.preventDefault();
    const delta = e.deltaY > 0 ? -ZOOM_STEP : ZOOM_STEP;
    setScale((s) => Math.min(MAX_SCALE, Math.max(MIN_SCALE, s + delta)));
  }, []);

  const handlePointerDown = useCallback((e: React.PointerEvent) => {
    dragRef.current = { startX: e.clientX, startY: e.clientY, origX: translate.x, origY: translate.y };
    (e.target as HTMLElement).setPointerCapture(e.pointerId);
  }, [translate]);

  const handlePointerMove = useCallback((e: React.PointerEvent) => {
    if (!dragRef.current) return;
    setTranslate({
      x: dragRef.current.origX + (e.clientX - dragRef.current.startX),
      y: dragRef.current.origY + (e.clientY - dragRef.current.startY),
    });
  }, []);

  const handlePointerUp = useCallback(() => {
    dragRef.current = null;
  }, []);

  const resetView = useCallback(() => {
    setScale(1);
    setTranslate({ x: 0, y: 0 });
  }, []);

  if (!svg) {
    return (
      <div className="my-4 bg-rp-surface rounded-lg p-6 flex items-center justify-center">
        <span className="text-rp-muted text-r-sm">Rendering diagram...</span>
      </div>
    );
  }

  return (
    <div className="my-4 bg-rp-surface rounded-lg p-6">
      <div className="flex items-center gap-2 mb-2 text-r-xs text-rp-muted">
        <button onClick={() => setScale((s) => Math.min(MAX_SCALE, s + ZOOM_STEP))} className="px-2 py-0.5 rounded bg-rp-bg hover:bg-rp-border/20 transition-colors" title="Zoom in">+</button>
        <button onClick={() => setScale((s) => Math.max(MIN_SCALE, s - ZOOM_STEP))} className="px-2 py-0.5 rounded bg-rp-bg hover:bg-rp-border/20 transition-colors" title="Zoom out">−</button>
        <button onClick={resetView} className="px-2 py-0.5 rounded bg-rp-bg hover:bg-rp-border/20 transition-colors" title="Reset view">Reset</button>
        <span>{Math.round(scale * 100)}%</span>
      </div>
      <div
        className="overflow-hidden rounded cursor-grab active:cursor-grabbing"
        style={{ touchAction: "none" }}
        onWheel={handleWheel}
        onPointerDown={handlePointerDown}
        onPointerMove={handlePointerMove}
        onPointerUp={handlePointerUp}
      >
        <div
          ref={containerRef}
          className="flex justify-center [&_svg]:max-w-none origin-center transition-transform duration-100"
          style={{ transform: `translate(${translate.x}px, ${translate.y}px) scale(${scale})` }}
          dangerouslySetInnerHTML={{ __html: svg }}
        />
      </div>
    </div>
  );
}
