/* 灵次元 · 极简工具页 共享逻辑 */
const { useState, useEffect, useRef, useCallback } = React;

function Icon({ name, cls }) {
  const ref = useRef(null);
  useEffect(() => {
    const host = ref.current;
    if (!host || !window.lucide) return;
    host.innerHTML = '<i data-lucide="' + name + '"></i>';
    try { window.lucide.createIcons(); } catch (e) {}
  }, [name]);
  return <span ref={ref} className={"ic " + (cls || "")}></span>;
}

function useTheme() {
  const [theme, setTheme] = useState(() => document.documentElement.getAttribute("data-theme") || "light");
  useEffect(() => {
    document.documentElement.setAttribute("data-theme", theme);
    try { localStorage.setItem("lcy-theme", theme); } catch (e) {}
  }, [theme]);
  return [theme, () => setTheme((t) => (t === "light" ? "dark" : "light"))];
}

async function aiComplete(prompt) {
  // 接入真实后端（通义千问）。兼容旧的沙箱 window.claude（若存在则优先用）。
  if (window.claude && typeof window.claude.complete === "function") {
    return (await window.claude.complete(prompt) || "").trim();
  }
  let res;
  try {
    res = await fetch("/api/complete", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ prompt }),
    });
  } catch (e) { throw new Error("AI_UNAVAILABLE"); }
  if (!res.ok) throw new Error("AI_UNAVAILABLE");
  const j = await res.json();
  return (j.text || "").trim();
}

// robust JSON extraction: strips code fences, falls back to outermost braces/brackets
function parseJSON(s) {
  let t = (s || "").trim().replace(/^```(?:json)?/i, "").replace(/```$/, "").trim();
  try { return JSON.parse(t); } catch (e) {}
  const starts = ["{", "["].map((c) => t.indexOf(c)).filter((i) => i >= 0);
  const first = starts.length ? Math.min.apply(null, starts) : -1;
  const last = Math.max(t.lastIndexOf("}"), t.lastIndexOf("]"));
  if (first >= 0 && last > first) return JSON.parse(t.slice(first, last + 1));
  throw new Error("PARSE");
}

function AppBar({ icon, name, sub }) {
  const [theme, toggle] = useTheme();
  // share theme state up via a custom event-free approach: each app uses its own AppBar instance,
  // but we keep a single source by reading attribute. To keep toggle working we expose it here.
  return (
    <div className="appbar">
      <a className="brand" href="灵次元AI主页.html">
        <span className="mk"><Icon name={icon} /></span>
        <span className="nm"><b>{name}</b><span>{sub}</span></span>
      </a>
      <a className="back" href="灵次元AI主页.html"><Icon name="grid-3x3" />应用中心</a>
      <button className="iconbtn" onClick={toggle} title="主题"><Icon name={theme === "light" ? "moon" : "sun"} /></button>
    </div>
  );
}

function Toast({ msg }) {
  if (!msg) return null;
  return <div className="toast"><Icon name="check-circle-2" />{msg}</div>;
}

function ScoreRing({ score }) {
  const r = 40, c = 2 * Math.PI * r;
  const off = c * (1 - score / 100);
  const col = score >= 85 ? "var(--ok)" : score >= 70 ? "var(--warn)" : "var(--live)";
  return (
    <div className="ring">
      <svg viewBox="0 0 92 92">
        <circle cx="46" cy="46" r={r} fill="none" stroke="var(--surface-2)" strokeWidth="7" />
        <circle cx="46" cy="46" r={r} fill="none" stroke={col} strokeWidth="7" strokeLinecap="round"
          strokeDasharray={c} strokeDashoffset={off} style={{ transition: "stroke-dashoffset .8s cubic-bezier(.2,.8,.2,1)" }} />
      </svg>
      <span className="num" style={{ color: col }}>{score}</span>
    </div>
  );
}

function useToast() {
  const [msg, setMsg] = useState(null);
  const t = useRef(null);
  const flash = useCallback((m) => { setMsg(m); clearTimeout(t.current); t.current = setTimeout(() => setMsg(null), 1900); }, []);
  return [msg, flash];
}

function failMsg(e) { return e && e.message === "AI_UNAVAILABLE" ? "AI 暂不可用，请在联网环境体验生成功能" : "出错了，稍后再试～"; }

/* ============================================================
 * 共享 UI 组件库 —— 所有应用页统一复用，新增应用直接 import 使用
 * ============================================================ */

/* 全局 toast：CopyBtn 等组件无需 prop 传递即可提示 */
let _flash = null;
function GlobalToast() {
  const [msg, setMsg] = useState(null);
  const tr = useRef(null);
  useEffect(() => {
    _flash = (m) => { setMsg(m); clearTimeout(tr.current); tr.current = setTimeout(() => setMsg(null), 1900); };
    return () => { _flash = null; };
  }, []);
  return <Toast msg={msg} />;
}
function flash(m) { if (_flash) _flash(m); }

/* 页面外壳：顶栏 + 内容列 + 全局 toast。col 传 "split" / "wide" 等额外类名 */
function Page({ icon, name, sub, col, children }) {
  return (
    <div className="shell">
      <AppBar icon={icon} name={name} sub={sub} />
      <div className="page"><div className={"col" + (col ? " " + col : "")}>{children}</div></div>
      <GlobalToast />
    </div>
  );
}

/* 页眉文案块 */
function Intro({ eyebrow, title, sub, children }) {
  return (
    <div className="intro">
      {eyebrow && <div className="eyebrow">{eyebrow}</div>}
      {title && <h1>{title}</h1>}
      {sub && <p>{sub}</p>}
      {children}
    </div>
  );
}

/* 带标签的表单字段 */
function Field({ icon, label, opt, children, style }) {
  return (
    <div className="field" style={style}>
      {(label || icon) && <label>{icon && <Icon name={icon} />}{label}{opt && <span className="opt"> · {opt}</span>}</label>}
      {children}
    </div>
  );
}

/* 分段选择器。options 支持 ["文本"] 或 [{id,label}] */
function Seg({ options, value, onChange, style }) {
  return (
    <div className="seg" style={style}>
      {options.map((o) => {
        const id = o && o.id != null ? o.id : o;
        const label = o && o.label != null ? o.label : o;
        return <button key={id} className={value === id ? "on" : ""} onClick={() => onChange(id)}>{label}</button>;
      })}
    </div>
  );
}

/* 大块模式卡选择器。options: [{id, ic, t, d}] */
function Modes({ options, value, onChange, style }) {
  return (
    <div className="modes" style={style}>
      {options.map((m) => (
        <button key={m.id} className={"mode" + (value === m.id ? " on" : "")} onClick={() => onChange(m.id)}>
          <span className="mic"><Icon name={m.ic} /></span>
          <span><span className="mt">{m.t}</span><span className="md">{m.d}</span></span>
        </button>
      ))}
    </div>
  );
}

/* 生成按钮行 */
function GenBtn({ onClick, busy, label, busyLabel, icon = "sparkles", hint, disabled, children }) {
  return (
    <div className="gen-row">
      <button className="btn btn-primary" onClick={onClick} disabled={busy || disabled}>
        <Icon name={icon} />{busy ? busyLabel || "生成中…" : label}
      </button>
      {hint && <span className="gen-hint">{hint}</span>}
      {children}
    </div>
  );
}

/* 复制按钮（用全局 flash 提示）。text 可为字符串或返回字符串的函数 */
function CopyBtn({ text, label = "复制", icon = "copy" }) {
  return (
    <button className="btn btn-ghost btn-sm" style={{ padding: "7px 13px", fontSize: 13 }}
      onClick={() => { navigator.clipboard.writeText(typeof text === "function" ? text() : text || ""); flash("已复制"); }}>
      <Icon name={icon} />{label}
    </button>
  );
}

/* 结果卡片：可选表头（图标/标题/复制/自定义动作）+ 主体 */
function ResultCard({ icon, title, copy, actions, children, style, bodyStyle, headStyle, onHeadClick }) {
  const hasHead = title != null || icon || copy != null || actions;
  return (
    <div className="result-card" style={style}>
      {hasHead && (
        <div className="rc-head" style={headStyle} onClick={onHeadClick}>
          {icon && <Icon name={icon} />}{title}
          {(copy != null || actions) && <div className="acts">{copy != null && <CopyBtn text={copy} />}{actions}</div>}
        </div>
      )}
      {children != null && <div className="rc-body" style={bodyStyle}>{children}</div>}
    </div>
  );
}

/* 加载占位卡 */
function BusyCard({ label = "AI 正在生成…" }) {
  return <div className="result-card"><div className="rc-body"><div className="busy-row"><span className="spinner"></span>{label}</div></div></div>;
}

/* 富文本块（保留换行） */
function Rich({ children, muted, style }) {
  return <div className={"rich" + (muted ? " muted" : "")} style={style}>{children}</div>;
}

/* 列表条目：圆点 + 文本 + 可选尾部元素 */
function LI({ children, dot = true, dotColor, end, style }) {
  return (
    <div className="li" style={style}>
      {dot && <span className="dot" style={dotColor ? { background: dotColor } : null}></span>}
      <span className="tx">{children}</span>
      {end}
    </div>
  );
}

Object.assign(window, {
  LCYIcon: Icon, useTheme, aiComplete, parseJSON, AppBar, Toast, ScoreRing, useToast, failMsg,
  GlobalToast, flash, Page, Intro, Field, Seg, Modes, GenBtn, CopyBtn, ResultCard, BusyCard, Rich, LI,
});
