/* ============================================================
   谁是天眼 · 主要页面 → window
   ============================================================ */

/* ---------------- 首页 ---------------- */
function HomeScreen({ go }) {
  const summary = Store.getSummary();
  const total = summary.total || 0;
  const active = summary.active || 0;
  return (
    <div className="page">
      <div className="wrap">
        <div className="hero">
          <span className="eye-emblem"><img src="assets/logo.png" alt="" /></span>
          <h1>谁是天眼</h1>
          <div className="tagline">剧本杀玩家信用查询 · 玩家共建</div>
          <p className="lede">
            由门店与组织者共同维护的"天眼"提示档案。提前知本、恶意剧透、串通刷本——
            登记一次，玩家共查。数据不公开浏览，仅支持凭微信号或特征信息<strong style={{ color: "var(--text)" }}>精确查询</strong>。
          </p>

          <div className="entry-grid">
            <div className="entry-card" onClick={() => go("query")}>
              <div className="ec-ico">{Icon.search({ s: 30 })}</div>
              <h3>查询档案</h3>
              <p>开场前核实拼场玩家。输入微信号或特征信息，命中即显示完整提示档案。</p>
              <span className="go">立即查询 {Icon.arrow({ s: 15 })}</span>
            </div>
            <div className="entry-card" onClick={() => go("register")}>
              <div className="ec-ico">{Icon.plus({ s: 30 })}</div>
              <h3>登记天眼</h3>
              <p>遇到天眼玩家？登记姓名、剧本、店铺与特征信息，为玩家留一份提示。</p>
              <span className="go">前往登记 {Icon.arrow({ s: 15 })}</span>
            </div>
          </div>

          <div className="stat-row">
            <div className="stat"><div className="num">{total}</div><div className="lbl">在册档案</div></div>
            <div className="stat"><div className="num">{active}</div><div className="lbl">生效提示</div></div>
            <div className="stat"><div className="num">{summary.dailyLimit || Store.getDailyLimit()}</div><div className="lbl">每 IP 日登记上限</div></div>
          </div>
        </div>

        <div className="notice" style={{ maxWidth: 720, margin: "10px auto 0" }}>
          <span className="ico">{Icon.warn({ s: 20 })}</span>
          <div>
            <strong>隐私与使用提示。</strong> 本平台仅作玩家信用提示之用，不对外公开浏览，所有查询行为均记录留痕。
            请勿登记与剧本杀信用无关的个人隐私信息；如被误登记，可在查到的档案上发起<strong>申诉</strong>，由管理员核实后撤档。
          </div>
        </div>
      </div>
    </div>
  );
}

/* ---------------- 查询页 ---------------- */
function QueryScreen({ go, onAppeal }) {
  const [terms, setTerms] = useState([""]);
  const [scopes, setScopes] = useState({ wechat: true, feature: true });
  const [submitted, setSubmitted] = useState(false);
  const [results, setResults] = useState([]);
  const [busy, setBusy] = useState(false);
  const toast = useToast();
  const cleanTerms = terms.map(t => t.trim()).filter(Boolean);

  const run = async (e) => {
    if (e) e.preventDefault();
    if (cleanTerms.length === 0) return;
    setBusy(true);
    try {
      setResults(await Store.query(cleanTerms, scopes));
      setSubmitted(true);
    } catch (err) {
      toast("查询失败，请稍后重试", "err");
    } finally {
      setBusy(false);
    }
  };

  const toggle = (k) => {
    const next = { ...scopes, [k]: !scopes[k] };
    if (!next.wechat && !next.feature) return; // 至少留一个
    setScopes(next);
  };
  const setTermAt = (i, v) => setTerms(ts => ts.map((t, idx) => idx === i ? v : t));
  const addTerm = () => setTerms(ts => [...ts, ""]);
  const rmTerm = (i) => setTerms(ts => ts.length <= 1 ? ts : ts.filter((_, idx) => idx !== i));

  return (
    <div className="page">
      <div className="wrap wrap-narrow">
        <div className="section-label"><span className="eyebrow">查询档案</span><span className="rule"></span></div>
        <h2 style={{ fontSize: 30, marginBottom: 8 }}>核实一位玩家</h2>
        <p style={{ color: "var(--text-mute)", fontSize: 14.5, lineHeight: 1.6, marginBottom: 26 }}>
          仅支持按 <b style={{ color: "var(--accent)" }}>微信号</b> 或 <b style={{ color: "var(--accent)" }}>其他特征信息</b>（迷圈ID、小红书ID、抖音号等）查询。
          姓名、剧本、店铺不可作为检索条件，以保护数据不被批量浏览。
        </p>

        <form onSubmit={run} style={{ display: "flex", flexDirection: "column", gap: 10 }}>
          {terms.map((term, i) => (
            <div className="search-box" key={i}>
              <span className="si">{Icon.search({ s: 20 })}</span>
              <input
                autoFocus={i === 0}
                placeholder="输入微信号 / 特征信息"
                value={term}
                onChange={e => setTermAt(i, e.target.value)}
              />
              {terms.length > 1 && (
                <button type="button" className="icon-btn danger" onClick={() => rmTerm(i)}>{Icon.x({ s: 14 })}</button>
              )}
              {i === terms.length - 1 && (
                <button type="button" className="icon-btn" onClick={addTerm}>{Icon.plus({ s: 15 })}</button>
              )}
            </div>
          ))}
          <button type="submit" className="btn btn-primary" disabled={cleanTerms.length === 0 || busy}>{busy ? "查询中…" : "查询"}</button>
        </form>
        <div className="scope-row">
          <span style={{ fontFamily: "var(--mono)", fontSize: 11, letterSpacing: "0.12em", color: "var(--text-faint)" }}>检索范围</span>
          <button className={"scope-chip" + (scopes.wechat ? " on" : "")} onClick={() => toggle("wechat")}>微信号</button>
          <button className={"scope-chip" + (scopes.feature ? " on" : "")} onClick={() => toggle("feature")}>其他特征信息</button>
        </div>

        {submitted && (
          <>
            <div className="result-meta">
              <span className="count">
                {results.length > 0
                  ? <>命中 <b>{results.length}</b> 条档案</>
                  : <>未命中任何档案</>}
              </span>
              <span style={{ fontFamily: "var(--mono)", fontSize: 11, color: "var(--text-faint)" }}>查询词「{cleanTerms.join(" / ")}」· 本次查询已留痕</span>
            </div>

            {results.length === 0 ? (
              <div className="empty-state">
                <div className="es-ico">{Icon.shield({ s: 44 })}</div>
                <h3>暂无信用提示</h3>
                <p>未在档案库中找到匹配记录。但请注意：无记录不等于完全安全，仍建议结合现场判断。</p>
              </div>
            ) : (
              <div className="dossier-stack">
                {results.map(r => <Dossier key={r.id} rec={r} onAppeal={onAppeal} />)}
              </div>
            )}
          </>
        )}

        {!submitted && (
          <div className="notice" style={{ marginTop: 26 }}>
            <span className="ico">{Icon.lock({ s: 18 })}</span>
            <div>数据不公开、不可枚举。仅当你提供准确的微信号或特征信息时才会返回对应档案，且每次查询均记录调用方与时间。</div>
          </div>
        )}
      </div>
    </div>
  );
}

/* ---------------- 登记页 ---------------- */
function RegisterScreen({ go }) {
  const toast = useToast();
  const [form, setForm] = useState({ nickname: "", script: "", shop: "", region: "", note: "" });
  const [features, setFeatures] = useState([{ type: "迷圈ID", value: "" }]);
  const [evidence, setEvidence] = useState([]);
  const [errors, setErrors] = useState({});
  const [done, setDone] = useState(null);
  const remaining = Store.remaining();
  const dailyLimit = Store.getDailyLimit();

  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const setFeat = (i, k, v) => setFeatures(fs => fs.map((f, idx) => idx === i ? { ...f, [k]: v } : f));
  const addFeat = () => setFeatures(fs => [...fs, { type: "迷圈ID", value: "" }]);
  const rmFeat = (i) => setFeatures(fs => fs.filter((_, idx) => idx !== i));

  const submit = async (e) => {
    e.preventDefault();
    const er = {};
    if (!form.nickname.trim()) er.nickname = "请填写天眼玩家的姓名 / 昵称";
    if (!form.script.trim()) er.script = "请填写涉及的剧本名称";
    if (!form.shop.trim()) er.shop = "请填写发生的店铺";
    const cleanFeatures = features.filter(f => f.value.trim());
    if (cleanFeatures.length === 0) {
      er.features = "请至少填写一条可查询的特征信息；微信号可不填";
    }
    setErrors(er);
    if (Object.keys(er).length) return;

    try {
      const wechatFeature = cleanFeatures.find(f => f.type === "微信号");
      const res = await Store.register({ ...form, wechat: wechatFeature ? wechatFeature.value : "", features: cleanFeatures, evidence });
      if (!res.ok && ["limit", "banned"].includes(res.reason)) {
        setDone({ limit: true, banned: res.reason === "banned" });
        toast(res.reason === "banned" ? "当前 IP 已被封禁" : "已触发后台风控提示", "err");
        return;
      }
      setDone({ record: res.record });
      toast("登记成功，档案已入库", "ok");
    } catch (err) {
      toast("提交失败，请稍后重试", "err");
    }
  };

  if (done) {
    return (
      <div className="page"><div className="wrap wrap-narrow">
        {done.limit ? (
          <div className="panel panel-pad" style={{ textAlign: "center" }}>
            <div style={{ color: "var(--stamp-red-ink)", marginBottom: 16 }}>{Icon.warn({ s: 48 })}</div>
            <h2 style={{ fontSize: 26, marginBottom: 12 }}>{done.banned ? "当前 IP 已被封禁" : "今日登记已达上限"}</h2>
            <p style={{ color: "var(--text-mute)", lineHeight: 1.7, maxWidth: 440, margin: "0 auto 8px" }}>
              {done.banned
                ? <>该 IP 暂不可继续登记。你的本次提交已被拦截，并已生成一条<strong style={{ color: "var(--stamp-red-ink)" }}>后台风控提示</strong>。</>
                : <>同一 IP 或同一设备每日最多登记 <b style={{ color: "var(--text)" }}>{dailyLimit}</b> 条。你的本次提交已被拦截，并已生成一条<strong style={{ color: "var(--stamp-red-ink)" }}>后台风控提示</strong>，管理员将留意异常登记行为。</>}
            </p>
            <p style={{ color: "var(--text-faint)", fontSize: 13, marginBottom: 22 }}>如确有多条需登记，请明日再来，或联系管理员说明情况。</p>
            <div style={{ display: "flex", gap: 12, justifyContent: "center" }}>
              <button className="btn btn-ghost" onClick={() => go("home")}>返回首页</button>
              <button className="btn btn-ghost" onClick={() => go("query")}>去查询</button>
            </div>
          </div>
        ) : (
          <div className="panel panel-pad" style={{ textAlign: "center" }}>
            <div style={{ color: "var(--safe)", marginBottom: 16 }}>{Icon.check({ s: 46 })}</div>
            <h2 style={{ fontSize: 26, marginBottom: 10 }}>档案已入库</h2>
            <p style={{ color: "var(--text-mute)", lineHeight: 1.7, marginBottom: 6 }}>
              编号 <b className="mono" style={{ color: "var(--accent)" }}>{done.record.id}</b> · 其他玩家现在可凭微信号或特征信息查询到此提示。
            </p>
            <p style={{ color: "var(--text-faint)", fontSize: 13, marginBottom: 22 }}>今日还可登记 {Store.remaining()} 条。感谢你的共建。</p>
            <div style={{ display: "flex", gap: 12, justifyContent: "center" }}>
              <button className="btn btn-primary" onClick={() => { setDone(null); setForm({ nickname: "", script: "", shop: "", region: "", note: "" }); setFeatures([{ type: "迷圈ID", value: "" }]); setEvidence([]); }}>继续登记</button>
              <button className="btn btn-ghost" onClick={() => go("home")}>返回首页</button>
            </div>
          </div>
        )}
      </div></div>
    );
  }

  return (
    <div className="page">
      <div className="wrap wrap-narrow">
        <div className="section-label"><span className="eyebrow">登记天眼</span><span className="rule"></span></div>
        <h2 style={{ fontSize: 30, marginBottom: 8 }}>登记一份信用提示</h2>
        <p style={{ color: "var(--text-mute)", fontSize: 14.5, lineHeight: 1.6, marginBottom: 18 }}>
          请如实填写。登记内容将用于玩家信用查询，被登记者有权申诉。恶意、虚假登记将被风控并撤档。
        </p>

        <div className={"notice" + (remaining === 0 ? " danger" : "")} style={{ marginBottom: 24 }}>
          <span className="ico">{remaining === 0 ? Icon.warn({ s: 18 }) : Icon.bell({ s: 18 })}</span>
          <div>
            {remaining === 0
              ? <>当前 IP 或设备 <strong>今日登记额度已用尽</strong>（每日 {dailyLimit} 条）。继续提交将触发后台提示。</>
              : <>当前 IP 与设备今日还可登记 <strong>{remaining}</strong> 条（每日上限 {dailyLimit} 条，防止滥用）。</>}
          </div>
        </div>

        <form className="panel panel-pad" onSubmit={submit}>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }}>
            <div className={"field" + (errors.nickname ? " error" : "")}>
              <label>姓名 / 昵称<span className="req">*</span></label>
              <input className="input" value={form.nickname} onChange={e => set("nickname", e.target.value)} placeholder="天眼玩家的常用称呼" />
              {errors.nickname && <div className="err-msg">{errors.nickname}</div>}
            </div>
            <div className={"field" + (errors.script ? " error" : "")}>
              <label>涉及剧本名称<span className="req">*</span></label>
              <input className="input" value={form.script} onChange={e => set("script", e.target.value)} placeholder="《剧本名》" />
              {errors.script && <div className="err-msg">{errors.script}</div>}
            </div>
          </div>

          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }}>
            <div className={"field" + (errors.shop ? " error" : "")}>
              <label>发生店铺<span className="req">*</span></label>
              <input className="input" value={form.shop} onChange={e => set("shop", e.target.value)} placeholder="门店名称（城市·分店）" />
              {errors.shop && <div className="err-msg">{errors.shop}</div>}
            </div>
            <div className="field">
              <label>城市</label>
              <input className="input" value={form.region} onChange={e => set("region", e.target.value)} placeholder="如：北京、成都、上海" />
            </div>
          </div>

          <div className={"field" + (errors.features ? " error" : "")}>
            <label>特征信息 <span style={{ color: "var(--text-faint)", fontWeight: 400 }}>（微信号可不填；请优先以微信号作为特征信息，可多条）</span></label>
            <div style={{ display: "flex", flexDirection: "column", gap: 9 }}>
              {features.map((f, i) => (
                <div key={i} style={{ display: "flex", gap: 8 }}>
                  <select className="select" style={{ flex: "0 0 130px" }} value={f.type} onChange={e => setFeat(i, "type", e.target.value)}>
                    {Store.FEATURE_TYPES.map(t => <option key={t}>{t}</option>)}
                  </select>
                  <input className="input" style={{ flex: 1 }} value={f.value} onChange={e => setFeat(i, "value", e.target.value)} placeholder={f.type === "微信号" ? "微信号（选填）" : "特征信息内容"} />
                  {features.length > 1 && (
                    <button type="button" className="icon-btn danger" style={{ flex: "0 0 auto" }} onClick={() => rmFeat(i)}>{Icon.trash({ s: 14 })}</button>
                  )}
                </div>
              ))}
            </div>
            {errors.features && <div className="err-msg">{errors.features}</div>}
            <button type="button" className="btn btn-ghost" style={{ marginTop: 10, padding: "9px 16px", fontSize: 13.5 }} onClick={addFeat}>{Icon.plus({ s: 15 })} 添加一条特征信息</button>
          </div>

          <div className="field">
            <label>情况说明</label>
            <textarea className="textarea" value={form.note} onChange={e => set("note", e.target.value)} placeholder="简述发生了什么：涉及哪类本、如何提前知本/影响游戏，是否有其他玩家或店家可佐证……" />
            <div className="hint">请客观陈述事实，避免人身攻击与无关隐私。</div>
          </div>

          <div className="field">
            <label>证据照片 <span style={{ color: "var(--text-faint)", fontWeight: 400 }}>（聊天截图、监控、组局记录等，最多 4 张）</span></label>
            <EvidenceUploader value={evidence} onChange={setEvidence} max={4} />
            <div className="hint">照片会随档案一并展示给查询者，请勿上传无关人员的隐私影像。</div>
          </div>

          <div style={{ display: "flex", gap: 12, marginTop: 8 }}>
            <button type="submit" className="btn btn-primary btn-lg" disabled={remaining === 0 ? false : false}>提交登记</button>
            <button type="button" className="btn btn-ghost btn-lg" onClick={() => go("home")}>取消</button>
          </div>
        </form>
      </div>
    </div>
  );
}

/* ---------------- 投诉建议页 ---------------- */
function FeedbackScreen({ go }) {
  const toast = useToast();
  const [content, setContent] = useState("");
  const [contact, setContact] = useState("");
  const [sent, setSent] = useState(false);
  const [err, setErr] = useState({});

  const submit = async (e) => {
    e.preventDefault();
    const nextErr = {};
    if (content.trim().length < 6) nextErr.content = "请至少填写 6 个字";
    setErr(nextErr);
    if (Object.keys(nextErr).length) return;
    try {
      await Store.submitFeedback({ content, contact });
      setSent(true);
      toast("已提交给管理员", "ok");
    } catch {
      toast("提交失败，请稍后重试", "err");
    }
  };

  if (sent) {
    return (
      <div className="page"><div className="wrap wrap-narrow">
        <div className="panel panel-pad" style={{ textAlign: "center" }}>
          <div style={{ color: "var(--safe)", marginBottom: 16 }}>{Icon.check({ s: 46 })}</div>
          <h2 style={{ fontSize: 26, marginBottom: 10 }}>已提交给管理员</h2>
          <p style={{ color: "var(--text-mute)", lineHeight: 1.7, marginBottom: 22 }}>管理员会在后台看到这条投诉建议，并按情况处理。</p>
          <button className="btn btn-primary" onClick={() => go("home")}>返回首页</button>
        </div>
      </div></div>
    );
  }

  return (
    <div className="page">
      <div className="wrap wrap-narrow">
        <div className="section-label"><span className="eyebrow">投诉建议</span><span className="rule"></span></div>
        <h2 style={{ fontSize: 30, marginBottom: 8 }}>联系管理员</h2>
        <p style={{ color: "var(--text-mute)", fontSize: 14.5, lineHeight: 1.6, marginBottom: 24 }}>
          关于误登记、恶意登记、页面问题或其他建议，可以直接提交到管理员后台。
        </p>
        <form className="panel panel-pad" onSubmit={submit}>
          <div className={"field" + (err.content ? " error" : "")}>
            <label>投诉建议<span className="req">*</span></label>
            <textarea className="textarea" value={content} onChange={e => setContent(e.target.value)} placeholder="请说明问题、相关档案编号或你希望管理员处理的事项" />
            {err.content && <div className="err-msg">{err.content}</div>}
          </div>
          <div className="field">
            <label>联系方式</label>
            <input className="input" value={contact} onChange={e => setContact(e.target.value)} placeholder="微信 / 手机 / 其他联系方式（选填）" />
          </div>
          <div style={{ display: "flex", gap: 12 }}>
            <button className="btn btn-primary btn-lg" type="submit">提交给管理员</button>
            <button className="btn btn-ghost btn-lg" type="button" onClick={() => go("home")}>取消</button>
          </div>
        </form>
      </div>
    </div>
  );
}

/* ---------------- 申诉模态 ---------------- */
function AppealModal({ rec, onClose }) {
  const toast = useToast();
  const [reason, setReason] = useState("");
  const [contact, setContact] = useState("");
  const [evidence, setEvidence] = useState([]);
  const [err, setErr] = useState({});

  const submit = async () => {
    const e = {};
    if (reason.trim().length < 10) e.reason = "请至少用 10 个字说明申诉理由";
    if (!contact.trim()) e.contact = "请留下联系方式以便核实";
    setErr(e);
    if (Object.keys(e).length) return;
    try {
      await Store.submitAppeal(rec.id, { reason, contact, evidence });
      toast("申诉已提交，等待管理员审核", "ok");
      onClose();
    } catch (err) {
      toast("申诉提交失败，请稍后重试", "err");
    }
  };

  return (
    <Modal
      title="发起申诉"
      sub={"针对档案 " + rec.id + " · " + rec.nickname}
      onClose={onClose}
      foot={<>
        <button className="btn btn-primary btn-block" onClick={submit}>{Icon.gavel({ s: 16 })} 提交申诉</button>
        <button className="btn btn-ghost" onClick={onClose}>取消</button>
      </>}
    >
      <div className="notice" style={{ marginBottom: 18 }}>
        <span className="ico">{Icon.warn({ s: 18 })}</span>
        <div>提交后该档案将进入<strong>「申诉处理中」</strong>状态，管理员核实后会撤档或维持。请提供尽可能具体的事实与佐证。</div>
      </div>
      <div className={"field" + (err.reason ? " error" : "")}>
        <label>申诉理由<span className="req">*</span></label>
        <textarea className="textarea" value={reason} onChange={e => setReason(e.target.value)} placeholder="说明为何认为该记录不实或应撤档，例如：当天为首次拼场、有现场监控或组局记录可证……" />
        {err.reason && <div className="err-msg">{err.reason}</div>}
      </div>
      <div className={"field" + (err.contact ? " error" : "")}>
        <label>联系方式<span className="req">*</span></label>
        <input className="input" value={contact} onChange={e => setContact(e.target.value)} placeholder="微信 / 手机，仅管理员可见" />
        {err.contact && <div className="err-msg">{err.contact}</div>}
      </div>
      <div className="field" style={{ marginBottom: 0 }}>
        <label>佐证照片 <span style={{ color: "var(--text-faint)", fontWeight: 400 }}>（选填，有助于加快核实）</span></label>
        <EvidenceUploader value={evidence} onChange={setEvidence} max={4} />
      </div>
    </Modal>
  );
}

Object.assign(window, { HomeScreen, QueryScreen, RegisterScreen, FeedbackScreen, AppealModal });
