import React, { useState, useEffect, useRef, useCallback } from "react";
import { NodeViewWrapper } from "@tiptap/react";
import type { NodeViewProps } from "@tiptap/react";
import mermaid from "mermaid";

let currentMermaidTheme: string | null = null;

function getMermaidTheme(): "dark" | "neutral" {
  return document.documentElement.getAttribute("data-theme") === "dark"
    ? "dark"
    : "neutral";
}

function ensureMermaidInit(forceReinit = false) {
  const desired = getMermaidTheme();
  if (currentMermaidTheme === desired && !forceReinit) return;
  mermaid.initialize({
    startOnLoad: false,
    theme: desired,
    securityLevel: "loose",
    fontFamily: "var(--default-font-family)",
  });
  currentMermaidTheme = desired;
}

export function MermaidNodeView({ node, updateAttributes }: NodeViewProps) {
  const code = (node.attrs.code as string) || "";
  const [editing, setEditing] = useState(!code);
  const [draft, setDraft] = useState(code);
  const [svgHtml, setSvgHtml] = useState("");
  const [error, setError] = useState("");
  const renderIdRef = useRef(0);
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  const previewRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!editing) setDraft(code);
  }, [code, editing]);

  useEffect(() => {
    if (editing && textareaRef.current) {
      textareaRef.current.focus();
      textareaRef.current.selectionStart = textareaRef.current.value.length;
    }
  }, [editing]);

  const renderDiagram = useCallback(async (src: string) => {
    if (!src.trim()) {
      setSvgHtml("");
      setError("");
      return;
    }
    ensureMermaidInit();
    const id = `mermaid-${++renderIdRef.current}`;
    try {
      const { svg } = await mermaid.render(id, src);
      setSvgHtml(svg);
      setError("");
    } catch (err: any) {
      setError(err?.message || "Invalid diagram");
      const stale = document.getElementById(id);
      stale?.remove();
    }
  }, []);

  useEffect(() => {
    renderDiagram(code);
  }, [code, renderDiagram]);

  // Update shadow DOM only when svgHtml changes (not on every render)
  useEffect(() => {
    const el = previewRef.current;
    if (!el || !svgHtml) return;
    const shadow = el.shadowRoot ?? el.attachShadow({ mode: "open" });
    shadow.innerHTML = `<div style="display:flex;justify-content:center">${svgHtml}</div>`;
  }, [svgHtml]);

  useEffect(() => {
    const observer = new MutationObserver((mutations) => {
      for (const m of mutations) {
        if (m.attributeName === "data-theme") {
          ensureMermaidInit(true);
          renderDiagram(code);
          break;
        }
      }
    });
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["data-theme"],
    });
    return () => observer.disconnect();
  }, [code, renderDiagram]);

  const commit = useCallback(() => {
    setEditing(false);
    if (draft !== code) {
      updateAttributes({ code: draft });
    }
  }, [draft, code, updateAttributes]);

  return (
    <NodeViewWrapper data-component="mermaid">
      <div
        contentEditable={false}
        style={{
          border: "1px solid var(--border-color)",
          borderRadius: 8,
          overflow: "hidden",
          margin: "0.75em 0",
          userSelect: "none",
        }}
      >
        {/* Header */}
        <div
          style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "space-between",
            padding: "6px 12px",
            borderBottom: "1px solid var(--border-color)",
            background: "var(--surface-bg)",
          }}
        >
          <span style={{ fontSize: 12, fontWeight: 600, color: "var(--muted-color)" }}>
            ◈ Mermaid
          </span>
          <button
            onClick={() => {
              if (editing) commit();
              else setEditing(true);
            }}
            style={{
              background: "none",
              border: "1px solid var(--border-color)",
              borderRadius: 4,
              padding: "2px 10px",
              fontSize: 11,
              color: "var(--muted-color)",
              cursor: "pointer",
            }}
          >
            {editing ? "Done" : "Edit"}
          </button>
        </div>

        {/* Code editor (shown when editing) */}
        {editing && (
          <div style={{ borderBottom: "1px solid var(--border-color)" }}>
            <textarea
              ref={textareaRef}
              value={draft}
              onChange={(e) => setDraft(e.target.value)}
              onBlur={commit}
              onKeyDown={(e) => {
                if (e.key === "Escape") {
                  setDraft(code);
                  setEditing(false);
                }
                if (e.key === "Tab") {
                  e.preventDefault();
                  const ta = e.currentTarget;
                  const start = ta.selectionStart;
                  const end = ta.selectionEnd;
                  const val = ta.value;
                  const updated = val.substring(0, start) + "  " + val.substring(end);
                  setDraft(updated);
                  requestAnimationFrame(() => {
                    ta.selectionStart = ta.selectionEnd = start + 2;
                  });
                }
              }}
              spellCheck={false}
              style={{
                width: "100%",
                minHeight: 120,
                padding: "12px 16px",
                border: "none",
                outline: "none",
                resize: "vertical",
                fontFamily: "var(--font-mono)",
                fontSize: 13,
                lineHeight: 1.5,
                background: "var(--code-bg)",
                color: "var(--text-color)",
                boxSizing: "border-box",
              }}
            />
          </div>
        )}

        {/* Preview */}
        {error ? (
          <div style={{ padding: "16px", color: "var(--danger-color, #dc2626)", fontSize: 12 }}>
            {error}
          </div>
        ) : svgHtml ? (
          <div
            style={{ padding: "16px", display: "flex", justifyContent: "center" }}
            ref={previewRef}
          />
        ) : (
          <div style={{ padding: "24px", textAlign: "center", color: "var(--muted-color)", fontSize: 13 }}>
            Click "Edit" to write a Mermaid diagram
          </div>
        )}
      </div>
    </NodeViewWrapper>
  );
}

MermaidNodeView.displayName = "MermaidView";
