/* gallery.jsx — home: grid gallery of mapped apps + real Add-App modal (server-backed) */

function AppIconBox({ app, s = 44 }) {
  return <AppIcon icon={app.icon || {}} s={s} radius={0.26} />;
}

function StatusBadge({ app }) {
  const base = { position: "absolute", top: 14, right: 14, display: "flex", alignItems: "center", gap: 6, padding: "4px 9px", borderRadius: 99, whiteSpace: "nowrap", backdropFilter: "blur(4px)" };
  if (app.status === "done") return (
    <div style={{ ...base, background: "rgba(91,208,106,.14)", border: "1px solid rgba(91,208,106,.3)" }}>
      <span style={{ width: 6, height: 6, borderRadius: 99, background: "var(--ok)", boxShadow: "0 0 6px var(--ok)" }} />
      <span className="mono" style={{ fontSize: 9.5, letterSpacing: ".12em", color: "var(--ok)" }}>已测绘</span>
    </div>
  );
  if (app.status === "pending") return (
    <div style={{ ...base, background: "rgba(245,185,69,.14)", border: "1px solid rgba(245,185,69,.3)" }}>
      <span style={{ width: 6, height: 6, borderRadius: 99, background: "var(--n-amber)" }} />
      <span className="mono" style={{ fontSize: 9.5, letterSpacing: ".12em", color: "var(--n-amber)" }}>待采集</span>
    </div>
  );
  return (
    <div style={{ ...base, background: "rgba(255,255,255,.05)", border: "1px solid var(--line-2)" }}>
      <span style={{ width: 6, height: 6, borderRadius: 99, background: "var(--t-faint)" }} />
      <span className="mono" style={{ fontSize: 9.5, letterSpacing: ".12em", color: "var(--t-dim)" }}>无地图</span>
    </div>
  );
}

/* hero: real first screenshot when available, else stylized placeholder phone */
function CardHero({ app, lift }) {
  const done = app.status === "done";
  return (
    <div style={{ height: 268, position: "relative", overflow: "hidden", background: "#050507", borderBottom: "1px solid var(--line)" }}>
      <div style={{ position: "absolute", left: "50%", top: 26, transform: `translateX(-50%) translateY(${lift ? -6 : 0}px)`, transition: "transform .3s",
        filter: done ? "none" : "grayscale(.5)", opacity: done ? 1 : 0.78 }}>
        {app.cover
          ? <img src={app.cover} alt="" draggable={false} style={{ width: 206, height: 206 * 2.04, objectFit: "cover", borderRadius: 26, border: "1px solid rgba(255,255,255,.14)", boxShadow: "0 6px 18px -6px rgba(0,0,0,.6)" }} onError={(e) => { e.currentTarget.style.display = "none"; }} />
          : <Phone arch={app.arch || "home"} accent={app.accent || "violet"} w={206} />}
      </div>

      <StatusBadge app={app} />
    </div>
  );
}

function AppCard({ app, onDetail }) {
  const [hover, setHover] = useState(false);
  const done = app.status === "done";
  const lift = hover;
  const aiPending = app.aiStatus === "running" || app.aiStatus === "queued";

  return (
    <div className="card" onClick={onDetail}
      onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{ overflow: "hidden", display: "flex", flexDirection: "column", cursor: "pointer",
        borderColor: lift ? "var(--line-2)" : "var(--line)", background: "var(--panel)",
        transition: "border-color .15s, transform .15s, box-shadow .15s",
        transform: lift ? "translateY(-2px)" : "none",
        boxShadow: lift ? "0 16px 40px -18px rgba(0,0,0,.7)" : "none" }}>
      <CardHero app={app} lift={lift} />

      <div style={{ padding: "18px 20px 18px", display: "flex", flexDirection: "column", gap: 13, flex: 1 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 13 }}>
          <AppIconBox app={app} s={42} />
          <div style={{ minWidth: 0 }}>
            <div style={{ color: "var(--t-hi)", fontWeight: 600, fontSize: 18, lineHeight: 1.15, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{app.name}</div>
            <div style={{ color: "var(--t-faint)", fontSize: 12, marginTop: 2 }}>{app.sub} · iOS</div>
          </div>
        </div>
        <div style={{ display: "flex", flexWrap: "wrap", gap: 7, marginTop: 2 }}>
          {done && app.trans > 0 && <span className="pill" style={{ height: 22, color: "var(--acc-hi)", borderColor: "rgba(139,124,246,.3)", background: "var(--acc-soft)" }}>{app.trans} screens</span>}
          {aiPending && <span className="pill" style={{ height: 22, color: "var(--acc-hi)", borderColor: "rgba(139,124,246,.3)", display: "inline-flex", gap: 5 }}><span className="spin" style={{ width: 8, height: 8, border: "1.5px solid var(--acc-soft)", borderTopColor: "var(--acc-hi)", borderRadius: "50%" }} />AI 分析中</span>}
          {(app.tags || []).map(t => <span key={t} className="pill" style={{ height: 22 }}>{t}</span>)}
        </div>
      </div>
    </div>
  );
}

/* -------------------------- add modal (real, server-backed) -------------------------- */
const SAMPLE_URL = "https://apps.apple.com/cn/app/id389801252"; // Instagram

function AddAppModal({ onClose, onStart, readOnly }) {
  const [text, setText] = useState("");
  const [resolving, setResolving] = useState(false);
  const [resolved, setResolved] = useState(null);
  const [error, setError] = useState(null);
  const [submitting, setSubmitting] = useState(false);
  const url = text.trim().split("\n").map(s => s.trim()).filter(Boolean)[0] || "";

  useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose]);

  // debounced resolve
  useEffect(() => {
    setResolved(null); setError(null);
    if (!url || !/\d{5,}/.test(url)) return;
    let cancelled = false;
    setResolving(true);
    const t = setTimeout(async () => {
      try {
        const r = await CARTO.resolve(url);
        if (!cancelled) { setResolved(r); setResolving(false); }
      } catch (e) {
        if (!cancelled) { setError(e.message || "无法识别该链接"); setResolving(false); }
      }
    }, 450);
    return () => { cancelled = true; clearTimeout(t); };
  }, [url]);

  const submit = async () => {
    if (!resolved || submitting) return;
    setSubmitting(true);
    try {
      const r = await CARTO.addApp(url);
      onStart(r.id, resolved);
    } catch (e) {
      setError(e.message || "添加失败");
      setSubmitting(false);
    }
  };

  return (
    <div onClick={onClose} style={{ position: "fixed", inset: 0, zIndex: 200, background: "rgba(4,4,6,.66)", backdropFilter: "blur(6px)", display: "grid", placeItems: "center", padding: 24 }}>
      <div onClick={e => e.stopPropagation()} className="card fade-in" style={{ width: "100%", maxWidth: 540, background: "var(--panel)", boxShadow: "0 30px 80px -20px rgba(0,0,0,.8)" }}>
        <div style={{ padding: "20px 24px", display: "flex", alignItems: "center", justifyContent: "space-between", borderBottom: "1px solid var(--line)" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
            <Icon name="sparkle" s={16} c="var(--acc)" />
            <span style={{ color: "var(--t-hi)", fontWeight: 600, fontSize: 16, whiteSpace: "nowrap" }}>添加 App</span>
          </div>
          <div className="icon-btn" onClick={onClose}><Icon name="x" s={15} /></div>
        </div>

        <div style={{ padding: 24, display: "flex", flexDirection: "column", gap: 18 }}>
          <div>
            <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 10 }}>
              <Icon name="link" s={14} c="var(--acc)" />
              <span className="eyebrow" style={{ flex: 1 }}>App Store 链接</span>
              <span className="pill" style={{ height: 20, color: "var(--t)", borderColor: "var(--line-2)" }}>仅支持 iOS</span>
            </div>
            <div style={{ border: `1px solid ${error ? "var(--n-red)" : "var(--line)"}`, borderRadius: "var(--r)", background: "var(--bg)" }}>
              <textarea value={text} onChange={e => setText(e.target.value)} spellCheck={false} autoFocus
                placeholder="粘贴 App Store 链接，例如 https://apps.apple.com/cn/app/id570060128"
                style={{ width: "100%", minHeight: 72, resize: "vertical", background: "transparent", border: "none", outline: "none", color: "var(--t)", fontFamily: "var(--mono)", fontSize: 13, lineHeight: 1.8, padding: "12px 14px" }} />
            </div>
            <div style={{ marginTop: 8, display: "flex", justifyContent: "space-between", alignItems: "center" }}>
              <span style={{ fontSize: 11.5, color: error ? "var(--n-red)" : "var(--t-faint)" }}>{error || "粘贴链接后将自动从 App Store 拉取真实信息"}</span>
              <span onClick={() => setText(SAMPLE_URL)} style={{ fontSize: 11.5, color: "var(--acc-hi)", cursor: "pointer", fontFamily: "var(--mono)" }}>填入示例</span>
            </div>
          </div>

          {(resolving || resolved) && (
            <div>
              <div className="eyebrow" style={{ marginBottom: 9 }}>{resolving ? "识别中…" : "已识别 · 1 个 App"}</div>
              <div className="card" style={{ padding: "12px 14px", display: "flex", alignItems: "center", gap: 13, background: "var(--panel-2)" }}>
                {resolving
                  ? <div style={{ width: 38, height: 38, borderRadius: 10, background: "var(--raised)", display: "grid", placeItems: "center", flex: "none" }}><span className="spin" style={{ width: 16, height: 16, border: "2px solid var(--acc-soft)", borderTopColor: "var(--acc-hi)", borderRadius: "50%" }} /></div>
                  : <AppIcon icon={resolved.icon || {}} s={38} radius={0.26} />}
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ color: "var(--t-hi)", fontWeight: 600, fontSize: 14, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{resolving ? "正在解析…" : resolved.name}</div>
                  <div style={{ color: "var(--t-dim)", fontSize: 12 }}>{resolving ? " " : `${resolved.sub} · iOS`}</div>
                </div>
                {!resolving && (resolved.existed
                  ? <span style={{ color: "var(--t-dim)", fontFamily: "var(--mono)", fontSize: 11, whiteSpace: "nowrap" }}>已在库中</span>
                  : <span style={{ display: "flex", alignItems: "center", gap: 6, color: "var(--ok)", fontFamily: "var(--mono)", fontSize: 11, whiteSpace: "nowrap" }}><Icon name="check" s={13} c="var(--ok)" />已解析</span>)}
              </div>
            </div>
          )}
        </div>

        <div style={{ padding: "16px 24px", display: "flex", gap: 12, justifyContent: "flex-end", borderTop: "1px solid var(--line)" }}>
          <button className="btn btn-ghost" onClick={onClose}>取消</button>
          <button className="btn btn-primary" disabled={!resolved || submitting} onClick={submit}>
            {submitting
              ? <><span className="spin" style={{ width: 13, height: 13, border: "2px solid rgba(255,255,255,.4)", borderTopColor: "#fff", borderRadius: "50%" }} />{readOnly ? "提交中…" : "添加中…"}</>
              : <><Icon name="sparkle" s={14} c="#fff" />{readOnly ? "提交收录" : "添加并分析"}<Icon name="arrow" s={15} c="#fff" /></>}
          </button>
        </div>
      </div>
    </div>
  );
}

/* -------------------------- gallery screen -------------------------- */
function GalleryScreen({ library, onStart, onOpenDetail, toggleTheme, aiOk, readOnly }) {
  const [modal, setModal] = useState(false);
  return (
    <div style={{ height: "100vh", display: "flex", flexDirection: "column" }}>
      <MiniTop right={
        <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
          {!readOnly && aiOk === false && <span className="pill" style={{ height: 24, color: "var(--n-amber)", borderColor: "rgba(245,185,69,.3)" }}>AI 未配置 · 定位占位</span>}
          {/* 添加入口对所有人开放：线上提交进 D1 排队（待采集），本地走完整采集流程 */}
          <button className="btn btn-primary" style={{ height: 36 }} onClick={() => setModal(true)}>
            <Icon name="plus" s={14} c="#fff" />添加 App
          </button>
          <div className="icon-btn" onClick={toggleTheme}><Icon name="sun" s={15} /></div>
        </div>
      } />

      <div style={{ flex: 1, overflowY: "auto" }}>
        <div style={{ maxWidth: 1320, margin: "0 auto", padding: "30px 40px 60px" }}>
          {library.length === 0
            ? <div style={{ padding: "80px 0", textAlign: "center", color: "var(--t-dim)" }}>
                <div style={{ marginBottom: 14 }}><Icon name="grid" s={28} c="var(--t-faint)" /></div>
                {readOnly ? "地图库为空" : "地图库为空 · 点击右上角「添加 App」开始"}
              </div>
            : <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(360px, 1fr))", gap: 20 }}>
                {library.map(app => <AppCard key={app.id} app={app} onDetail={() => onOpenDetail(app)} />)}
              </div>}
        </div>
      </div>

      {modal && <AddAppModal readOnly={readOnly} onClose={() => setModal(false)} onStart={(id, info) => { setModal(false); onStart(id, info); }} />}
    </div>
  );
}

Object.assign(window, { GalleryScreen, AppCard, AddAppModal, AppIconBox });
