/* Honey Scripts — Reusable doc components: code block, callout, steps */

const { useState, useEffect, useRef, useMemo } = React;

/* Naive syntax highlighter — handles cfg / lua / bash well enough for the doc set. */
function highlightCode(code, lang) {
  if (!code) return [];
  const lines = code.split("\n");
  return lines.map((line, i) => {
    const tokens = [];
    let rest = line;
    // Comment: # or --
    const commentIdx = (() => {
      if (lang === "cfg" || lang === "bash" || lang === "sh") return line.indexOf("#");
      if (lang === "lua") return line.indexOf("--");
      return -1;
    })();
    if (commentIdx >= 0) {
      const before = line.slice(0, commentIdx);
      const comment = line.slice(commentIdx);
      pushToken(tokens, before, lang);
      tokens.push(<span className="tok-c" key="c">{comment}</span>);
    } else {
      pushToken(tokens, line, lang);
    }
    return <div key={i}>{tokens.length ? tokens : "\u00A0"}</div>;
  });
}
function pushToken(tokens, text, lang) {
  if (!text) return;
  const keywords = {
    cfg: ["ensure", "start", "stop", "set", "setr", "sets"],
    lua: ["Config", "local", "function", "end", "return", "if", "then", "else", "elseif", "true", "false", "nil"],
    bash: ["sudo", "cd", "ls", "echo", "export"],
  }[lang] || [];
  // Tokenize: strings, numbers, keywords, identifiers
  const re = /("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')|(\b\d+\.?\d*\b)|([A-Za-z_][A-Za-z0-9_]*)|(\s+)|([^\s])/g;
  let m, idx = 0, key = 0;
  while ((m = re.exec(text)) !== null) {
    const [match, str, num, word, ws, sym] = m;
    if (str) tokens.push(<span className="tok-s" key={key++}>{str}</span>);
    else if (num) tokens.push(<span className="tok-n" key={key++}>{num}</span>);
    else if (word) {
      if (keywords.includes(word)) tokens.push(<span className="tok-k" key={key++}>{word}</span>);
      else tokens.push(<span className="tok-f" key={key++}>{word}</span>);
    } else tokens.push(<span key={key++}>{match}</span>);
  }
}

function CodeBlock({ code, lang = "txt", title }) {
  const [copied, setCopied] = useState(false);
  const t = window.useT();
  const handleCopy = async () => {
    try { await navigator.clipboard.writeText(code); } catch {}
    setCopied(true);
    setTimeout(() => setCopied(false), 1500);
  };
  return (
    <div className="codeblock">
      <div className="codeblock-head">
        <span className="lang">
          <span className="dot"></span>
          <span>{title || lang}</span>
        </span>
        <button className={"copy-btn" + (copied ? " copied" : "")} onClick={handleCopy}>
          {copied ? <Icon.Check/> : <Icon.Copy/>}
          {copied ? t("copied") : t("copy")}
        </button>
      </div>
      <pre><code>{highlightCode(code, lang)}</code></pre>
    </div>
  );
}

/* Inline markdown-ish text: backticks → code, **bold** → strong, [text](url) → external link */
function MD({ children }) {
  if (typeof children !== "string") return children;
  const parts = [];
  let s = children;
  let key = 0;
  const re = /(`[^`]+`|\*\*[^*]+\*\*|\[[^\]]+\]\([^)]+\))/g;
  let last = 0, m;
  while ((m = re.exec(s)) !== null) {
    if (m.index > last) parts.push(s.slice(last, m.index));
    const tok = m[0];
    if (tok.startsWith("`"))      parts.push(<code key={key++}>{tok.slice(1, -1)}</code>);
    else if (tok.startsWith("**"))parts.push(<strong key={key++}>{tok.slice(2, -2)}</strong>);
    else {
      const mm = tok.match(/^\[([^\]]+)\]\(([^)]+)\)$/);
      if (mm) parts.push(<a key={key++} href={mm[2]} target="_blank" rel="noreferrer noopener">{mm[1]}</a>);
      else parts.push(tok);
    }
    last = m.index + tok.length;
  }
  if (last < s.length) parts.push(s.slice(last));
  return <>{parts}</>;
}

function Callout({ kind = "info", title, body }) {
  const t = window.useT();
  const labels = { info: t("info"), warn: t("warning"), tip: t("tip") };
  const iconMap = { info: <Icon.Info/>, warn: <Icon.Warn/>, tip: <Icon.Tip/> };
  return (
    <div className={"callout " + kind}>
      <span className="ico">{iconMap[kind]}</span>
      <div>
        <div className="callout-title">{title || labels[kind]}</div>
        <div className="callout-body"><MD>{body}</MD></div>
      </div>
    </div>
  );
}

window.CodeBlock = CodeBlock;
window.Callout = Callout;
window.MD = MD;

/* Escrow-style error card: red header, cause text, "Solution:" list */
function ErrorCard({ code, cause, solutions = [] }) {
  return (
    <div className="error-card">
      <div className="error-card-head">
        <span className="error-card-ico"><Icon.AlertCircle/></span>
        <code className="error-card-code">{code}</code>
      </div>
      <div className="error-card-body">
        {cause && <p className="error-card-cause"><MD>{cause}</MD></p>}
        {solutions.length > 0 && (
          <>
            <div className="error-card-soln-h">
              <Icon.Check/>
              <span>Solution</span>
            </div>
            <ul className="error-card-soln">
              {solutions.map((s, i) => <li key={i}><MD>{s}</MD></li>)}
            </ul>
          </>
        )}
      </div>
    </div>
  );
}
window.ErrorCard = ErrorCard;
