/* global React, marked, DOMPurify */
const { useState, useEffect, useRef, useLayoutEffect, useMemo } = React;

// ── Configure marked + DOMPurify once ────────────────────────────────────────
if (typeof marked !== "undefined") {
  marked.setOptions({ gfm: true, breaks: true });
}
if (typeof DOMPurify !== "undefined" && !DOMPurify.__rndHooked) {
  DOMPurify.addHook("afterSanitizeAttributes", (node) => {
    if (node.tagName === "A" && node.getAttribute("href")) {
      node.setAttribute("target", "_blank");
      node.setAttribute("rel", "noopener noreferrer");
    }
  });
  DOMPurify.__rndHooked = true;
}

function renderMarkdown(src) {
  if (!src) return "";
  if (typeof marked === "undefined" || typeof DOMPurify === "undefined") {
    const escaped = String(src).replace(/[&<>]/g, c => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;" }[c]));
    return escaped.replace(/\n/g, "<br/>");
  }
  const html = marked.parse(String(src));
  return DOMPurify.sanitize(html, {
    ADD_ATTR: ["target", "rel"],
    FORBID_TAGS: ["style", "script", "iframe"],
  });
}

// ── Rendered markdown view with collapse / expand ────────────────────────────
function MarkdownView({ source, collapsedHeight = 160, className = "", style }) {
  const [expanded, setExpanded]   = useState(false);
  const [overflows, setOverflows] = useState(false);
  const ref = useRef(null);

  const html = useMemo(() => renderMarkdown(source), [source]);

  useLayoutEffect(() => {
    if (!ref.current) return;
    const measure = () => {
      const el = ref.current;
      if (!el) return;
      setOverflows(el.scrollHeight > collapsedHeight + 4);
    };
    measure();
    const ro = new ResizeObserver(measure);
    ro.observe(ref.current);
    return () => ro.disconnect();
  }, [html, collapsedHeight]);

  const showCollapse = overflows && !expanded;

  return (
    <div className={"md-view-wrap " + className} style={style}>
      <div
        ref={ref}
        className={"md-view" + (showCollapse ? " md-view-collapsed" : "")}
        style={showCollapse ? { maxHeight: collapsedHeight } : undefined}
        dangerouslySetInnerHTML={{ __html: html }}
      />
      {overflows && (
        <button
          type="button"
          className="md-expand-btn"
          onClick={(e) => { e.stopPropagation(); setExpanded(v => !v); }}
        >
          {expanded ? "Collapse" : "Expand"}
        </button>
      )}
    </div>
  );
}

// ── Markdown editor (toolbar + textarea + preview tab) ───────────────────────
function MarkdownEditor({ value, onChange, onKeyDown, rows = 8, autoFocus = false, placeholder = "Write something… (Markdown supported)" }) {
  const [tab, setTab] = useState("write");
  const ref = useRef(null);

  useEffect(() => {
    if (autoFocus && tab === "write" && ref.current) {
      ref.current.focus();
      const el = ref.current;
      if (el.value) el.setSelectionRange(el.value.length, el.value.length);
    }
  }, [autoFocus, tab]);

  const wrapSelection = (before, after = before, placeholder = "") => {
    const el = ref.current;
    if (!el) return;
    const start = el.selectionStart;
    const end   = el.selectionEnd;
    const sel   = el.value.slice(start, end);
    const inner = sel || placeholder;
    const next  = el.value.slice(0, start) + before + inner + after + el.value.slice(end);
    onChange(next);
    requestAnimationFrame(() => {
      el.focus();
      const pos = start + before.length;
      el.setSelectionRange(pos, pos + inner.length);
    });
  };

  const linePrefix = (prefix) => {
    const el = ref.current;
    if (!el) return;
    const start = el.selectionStart;
    const end   = el.selectionEnd;
    const v     = el.value;
    const lineStart = v.lastIndexOf("\n", start - 1) + 1;
    const next = v.slice(0, lineStart) + prefix + v.slice(lineStart);
    onChange(next);
    requestAnimationFrame(() => {
      el.focus();
      const pos = end + prefix.length;
      el.setSelectionRange(pos, pos);
    });
  };

  const insertLink = () => {
    const el = ref.current;
    if (!el) return;
    const start = el.selectionStart;
    const end   = el.selectionEnd;
    const sel   = el.value.slice(start, end) || "link text";
    const snippet = `[${sel}](https://)`;
    const next = el.value.slice(0, start) + snippet + el.value.slice(end);
    onChange(next);
    requestAnimationFrame(() => {
      el.focus();
      const urlStart = start + sel.length + 3;
      el.setSelectionRange(urlStart, urlStart + 8);
    });
  };

  const handleToolbarMouseDown = (e) => e.preventDefault(); // keep textarea focus

  const Btn = ({ title, onClick, children }) => (
    <button
      type="button"
      className="md-tb-btn"
      title={title}
      onMouseDown={handleToolbarMouseDown}
      onClick={onClick}
      tabIndex={-1}
    >
      {children}
    </button>
  );

  return (
    <div className="md-editor">
      <div className="md-tabs">
        <button
          type="button"
          className={"md-tab" + (tab === "write" ? " active" : "")}
          onClick={() => setTab("write")}
        >Write</button>
        <button
          type="button"
          className={"md-tab" + (tab === "preview" ? " active" : "")}
          onClick={() => setTab("preview")}
        >Preview</button>
        {tab === "write" && (
          <div className="md-toolbar">
            <Btn title="Bold (Ctrl+B)" onClick={() => wrapSelection("**", "**", "bold")}><b>B</b></Btn>
            <Btn title="Italic (Ctrl+I)" onClick={() => wrapSelection("*", "*", "italic")}><i>I</i></Btn>
            <Btn title="Inline code" onClick={() => wrapSelection("`", "`", "code")}>{"<>"}</Btn>
            <span className="md-tb-sep" />
            <Btn title="Heading" onClick={() => linePrefix("## ")}>H</Btn>
            <Btn title="Bulleted list" onClick={() => linePrefix("- ")}>•</Btn>
            <Btn title="Numbered list" onClick={() => linePrefix("1. ")}>1.</Btn>
            <Btn title="Quote" onClick={() => linePrefix("> ")}>❝</Btn>
            <span className="md-tb-sep" />
            <Btn title="Link" onClick={insertLink}>🔗</Btn>
            <Btn title="Code block" onClick={() => wrapSelection("\n```\n", "\n```\n", "code")}>{"{ }"}</Btn>
          </div>
        )}
      </div>

      {tab === "write" ? (
        <textarea
          ref={ref}
          className="form-textarea md-textarea"
          value={value}
          rows={rows}
          placeholder={placeholder}
          onChange={e => onChange(e.target.value)}
          onKeyDown={(e) => {
            if (e.key === "b" && (e.ctrlKey || e.metaKey)) { e.preventDefault(); wrapSelection("**", "**", "bold"); return; }
            if (e.key === "i" && (e.ctrlKey || e.metaKey)) { e.preventDefault(); wrapSelection("*", "*", "italic"); return; }
            onKeyDown && onKeyDown(e);
          }}
        />
      ) : (
        <div className="md-preview">
          {value
            ? <div className="md-view" dangerouslySetInnerHTML={{ __html: renderMarkdown(value) }} />
            : <div className="md-preview-empty">Nothing to preview yet.</div>}
        </div>
      )}
    </div>
  );
}

// ── Inline-editable markdown field (parallels InlineField) ───────────────────
function InlineMarkdownField({ value, onSave, placeholder = "Click to add…", collapsedHeight = 160, rows = 8 }) {
  const [editing, setEditing] = useState(false);
  const [draft, setDraft]     = useState("");
  const [saving, setSaving]   = useState(false);
  const [error, setError]     = useState(null);
  const mouseDownPos          = useRef(null);

  const startEdit = (e) => {
    if (e.target.closest && e.target.closest(".md-expand-btn, a")) return;
    const sel = window.getSelection();
    if (sel && sel.toString().length > 0) return;
    if (mouseDownPos.current) {
      const dx = Math.abs(e.clientX - mouseDownPos.current.x);
      const dy = Math.abs(e.clientY - mouseDownPos.current.y);
      if (dx > 4 || dy > 4) return;
    }
    setDraft(value ?? "");
    setError(null);
    setEditing(true);
  };

  const save = async () => {
    if (saving) return;
    setSaving(true);
    setError(null);
    try {
      await onSave(draft);
      setEditing(false);
    } catch (err) {
      setError(err.message || "Failed to save");
    } finally {
      setSaving(false);
    }
  };

  const cancel = () => { setEditing(false); setError(null); };

  const handleKeyDown = (e) => {
    if (e.key === "Escape") { e.preventDefault(); e.stopPropagation(); cancel(); return; }
    if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) { e.preventDefault(); save(); return; }
  };

  if (editing) {
    return (
      <div className="inline-edit-wrap">
        <MarkdownEditor
          value={draft}
          onChange={setDraft}
          onKeyDown={handleKeyDown}
          rows={rows}
          autoFocus
          placeholder={placeholder}
        />
        {error && <div className="inline-edit-error">{error}</div>}
        <div className="inline-edit-actions">
          <button className="btn btn-primary" style={{ height: 26, padding: "0 10px", fontSize: 12 }}
            onClick={save} disabled={saving}>
            {saving ? "Saving…" : "Save"}
          </button>
          <button className="btn btn-ghost" style={{ height: 26, padding: "0 8px", fontSize: 12 }}
            onClick={cancel} disabled={saving}>
            Cancel
          </button>
          <span style={{ fontSize: 11, color: "var(--text-4)", marginLeft: 2 }}>Ctrl+Enter to save</span>
        </div>
      </div>
    );
  }

  return (
    <div
      className="inline-field inline-field-md"
      onMouseDown={e => { mouseDownPos.current = { x: e.clientX, y: e.clientY }; }}
      onClick={startEdit}
    >
      {value
        ? <MarkdownView source={value} collapsedHeight={collapsedHeight} />
        : <span className="inline-field-placeholder">{placeholder}</span>}
      <span className="inline-field-icon">
        <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor"
             strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
          <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
          <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
        </svg>
      </span>
    </div>
  );
}

window.PRMarkdown = { MarkdownView, MarkdownEditor, InlineMarkdownField, renderMarkdown };
