/* 照野 — 私人命运地图（交互原型）
   过去已经显影，此刻成为锚点，远方化作道标。 */
const { useState, useEffect, useRef, useCallback } = React;
const D = window.ZY_DATA;

function StatusBar() {
  return (<div className="statusbar"><span className="t">23:47</span><StatusGlyphs /></div>);
}

function LensRail({ lens, onPick }) {
  return (
    <div className="lens-rail glass">
      {D.lenses.map(l => (
        <button key={l.id} className={"lens" + (lens === l.id ? " on" : "")} onClick={() => onPick(l.id)}>
          <Icon name={l.icon} size={15} stroke={2} />{l.name}
        </button>
      ))}
    </div>
  );
}

function Narrative({ idx, setIdx, onAct, cards }) {
  const list = cards || D.narrativeCards;
  const card = list[idx] || list[0];
  const down = useRef(null);
  const start = (e) => { down.current = e.clientX; };
  const end = (e) => {
    if (down.current == null) return;
    const dx = e.clientX - down.current; down.current = null;
    if (dx < -40) setIdx((idx + 1) % list.length);
    else if (dx > 40) setIdx((idx - 1 + list.length) % list.length);
  };
  return (
    <div className="narr glass" onPointerDown={start} onPointerUp={end}>
      <div className="kicker"><span className="dot" />{card.kicker}</div>
      <div className="line" key={card.id + "-l"} dangerouslySetInnerHTML={{ __html: card.html }} />
      <div className="acts">
        {card.acts.map((a, i) => (
          <button key={i} className={"act " + (a.k || "")} onClick={() => onAct(a)}>{a.t}</button>
        ))}
      </div>
      <div className="dots">
        {list.map((_, i) => (
          <i key={i} className={i === idx ? "on" : ""} onClick={() => setIdx(i)} />
        ))}
      </div>
    </div>
  );
}

function PlaceSheet({ id, onClose }) {
  const p = id ? D.places[id] : null;
  return (
    <React.Fragment>
      <div className={"scrim" + (id ? " show" : "")} onClick={onClose} />
      <div className={"sheet glass" + (id ? " show" : "")}>
        <div className="grip" />
        {p && (<React.Fragment>
          <div className="photo">
            {p.thumb && <img className="ph-img" src={p.thumb} alt="" />}
            <div className="grain" />
            <div className="ph-tag"><Icon name="photo" size={15} stroke={1.6} />{p.thumb ? "照片 · 由相册定位" : "照片 · 待放入"}</div>
          </div>
          <h2>{p.title}</h2>
          <div className="meta-loc">{p.loc}</div>
          <div className="yeyu">{p.yeyu.split("\n").map((s, i) => <div key={i}>{s}</div>)}</div>
          <div className="rows">
            <div className="row"><span className="k">到达</span><span className="v">{p.arrived}</span></div>
            <div className="row"><span className="k">谁一起</span><span className="v">{p.who}</span></div>
            <div className="row"><span className="k">来源</span><span className="v"><span className="src">{p.source} · {p.srcNote}</span></span></div>
          </div>
          <div className="sheet-acts">
            <div className="act">回看这段路</div>
            <div className="act primary">收为道标</div>
          </div>
        </React.Fragment>)}
      </div>
    </React.Fragment>
  );
}

function Companion({ view, setView, onClose }) {
  const v = D.companionViews.find(x => x.id === view);
  return (
    <React.Fragment>
      <div className="comp-top fade-y" key={view}>
        <div className="comp-head glass">
          <div className="ava">她</div>
          <div className="who"><div className="n">和 她 看地图</div><div className="s">你们的地图，长得不一样</div></div>
          <div className="close" onClick={onClose}><Icon name="close" size={20} /></div>
        </div>
        <div className="seg glass">
          {D.companionViews.map(cv => (
            <button key={cv.id} className={cv.id === view ? "on" : ""} onClick={() => setView(cv.id)}>{cv.name}</button>
          ))}
        </div>
        <div className="comp-legend glass">
          <div className="lg"><span className="sw" style={{ background: "var(--glow)" }} />你</div>
          <div className="lg"><span className="sw" style={{ background: "var(--her)" }} />她</div>
          {view === "wish" && <div className="lg"><span className="sw" style={{ background: "var(--waypoint)", boxShadow: "0 0 8px var(--waypoint)" }} />共同道标</div>}
        </div>
      </div>
      <div className="narr glass" key={"n" + view}>
        <div className="kicker"><span className="dot" />{v.kicker}</div>
        <div className="line" dangerouslySetInnerHTML={{ __html: v.line }} />
        {view === "both" && (
          <div className="line" style={{ fontSize: 14.5, color: "var(--text-dim)", marginTop: 12 }}
            dangerouslySetInnerHTML={{ __html: D.companionInsight }} />
        )}
        <div className="acts">
          {view === "wish"
            ? <button className="act primary">定为下一枚共同道标</button>
            : <button className="act primary">{view === "mine" ? "带她走一遍" : view === "hers" ? "请她带路" : "看我们的交点"}</button>}
        </div>
      </div>
    </React.Fragment>
  );
}

function Tweaks({ open, palette, density, setPalette, setDensity }) {
  const opt = (cur, val, label, em, on) => (
    <div className={"opt" + (cur === val ? " on" : "")} onClick={() => on(val)}>{label}<span className="em">{em}</span></div>
  );
  return (
    <div className={"tweaks glass" + (open ? " show" : "")}>
      <div className="grp">
        <div className="lbl">色温 · 显影之光</div>
        <div className="opts">
          {opt(palette, "warm", "暖 · 暗房", "琥珀显影", setPalette)}
          {opt(palette, "cool", "冷 · 星图", "命运冷光", setPalette)}
        </div>
      </div>
      <div className="grp">
        <div className="lbl">底图密度</div>
        <div className="opts">
          {opt(density, "quiet", "安静", "只留私人锚点", setDensity)}
          {opt(density, "public", "公共", "显出地名标注", setDensity)}
        </div>
      </div>
    </div>
  );
}

function Toast({ msg }) {
  return (<div style={{
    position: "absolute", left: "50%", bottom: 132, transform: "translateX(-50%)",
    zIndex: 48, padding: "11px 18px", borderRadius: 14, fontSize: 13.5,
    color: "var(--text)", maxWidth: 300, textAlign: "center", lineHeight: 1.5,
    background: "var(--glass)", border: ".5px solid var(--glass-line)",
    backdropFilter: "blur(20px)", WebkitBackdropFilter: "blur(20px)",
    opacity: msg ? 1 : 0, transition: "opacity .3s ease", pointerEvents: "none",
  }} dangerouslySetInnerHTML={{ __html: msg || "" }} />);
}

function App() {
  const mapEl = useRef(null);
  const [ready, setReady] = useState(false);
  const [scene, setScene] = useState("world");      // world | city | comp
  const [lens, setLens] = useState("develop");
  const [palette, setPalette] = useState("warm");
  const [density, setDensity] = useState("quiet");
  const [cardIdx, setCardIdx] = useState(0);
  const [placeId, setPlaceId] = useState(null);
  const [compView, setCompView] = useState("both");
  const [tweaksOpen, setTweaksOpen] = useState(false);
  const [toast, setToast] = useState("");
  const toastT = useRef(0);
  const [importing, setImporting] = useState(false);
  const [devCard, setDevCard] = useState(null);   // 导入后动态生成的「今晚新显影」卡
  const [devCoords, setDevCoords] = useState([]);
  const [dragging, setDragging] = useState(false);
  const fileRef = useRef(null);

  const cards = devCard ? [devCard, ...D.narrativeCards] : D.narrativeCards;

  const fireToast = useCallback((m) => {
    setToast(m); clearTimeout(toastT.current);
    toastT.current = setTimeout(() => setToast(""), 3200);
  }, []);

  // —— 照片显影（命门）——
  const runImport = useCallback(async (promise) => {
    setImporting(true);
    try { onImported(await promise); }
    catch (e) { fireToast("照片没能显影 · " + ((e && e.message) || "未知错误")); }
    finally { setImporting(false); }
  }, []); // eslint-disable-line

  const onImported = (r) => {
    if (!r || (!r.developed && !r.noGps)) { fireToast(r && r.error ? r.error : "没找到可显影的照片"); return; }
    setDevCoords(r.coords || []);
    const hit = r.hits && r.hits[0];
    const parts = [`今晚，你的地图新亮起 <em>${r.developed}</em> 个地方。`];
    if (hit) parts.push(`<br/>「${hit.name}」从道标，<em>显影</em>了。`);
    if (r.noGps) parts.push(`<br/><span style="font-size:13.5px;color:var(--text-dim)">还有 ${r.noGps} 张没有定位 —— 地图不假装知道它们在哪。</span>`);
    setDevCard({
      id: "__dev", kicker: "今晚 · 新显影", region: null, html: parts.join(""),
      acts: r.coords && r.coords.length
        ? [{ t: "去看看", k: "primary", go: "__refit" }, { t: "好", k: "ghost" }]
        : [{ t: "好", k: "ghost" }],
    });
    setCardIdx(0);
    if (devCard == null && scene === "world") ZyMap.setLens("develop");
    if (hit) fireToast(`「${hit.name}」显影了 · <em>你真的到过那里了</em>`);
    else fireToast(`新显影 ${r.developed} 处 · ${r.photos} 张照片落了地`);
  };

  const onPickFiles = (e) => { const fs = e.target.files; if (fs && fs.length) runImport(ZyDevelop.fromFiles(fs)); e.target.value = ""; };
  const onSamples = () => runImport(ZyDevelop.fromSamples());
  const onDrop = (e) => { e.preventDefault(); setDragging(false); const fs = e.dataTransfer && e.dataTransfer.files; if (fs && fs.length) runImport(ZyDevelop.fromFiles(fs)); };

  useEffect(() => {
    ZyMap.init(mapEl.current, {
      palette: "warm", density: "quiet",
      onReady: () => { setReady(true); ZyMap.setLens("develop"); },
    });
    ZyMap.onPlace((id) => setPlaceId(id));
    window.__openPlace = setPlaceId;
    window.__zy = {
      scene: (s) => setScene(s), comp: (v) => openComp(v), closeComp,
      lens: (l) => pickLens(l), palette: (p) => changePalette(p), place: setPlaceId,
    };
  }, []);

  // scene → camera
  useEffect(() => {
    if (!ready) return;
    if (scene === "world") { ZyMap.gotoWorld(); ZyMap.setLens(lens); }
    else if (scene === "city") ZyMap.gotoCity();
  }, [scene, ready]); // eslint-disable-line

  // night-roam: narrative card pans the map
  useEffect(() => {
    if (!ready || scene !== "world") return;
    const card = cards[cardIdx]; if (!card) return;
    if (card.id === "__dev") { if (devCoords.length) ZyMap.fitTo(devCoords); }
    else if (card.region) ZyMap.spotlight(card.region);
  }, [cardIdx, ready, scene, devCard]); // eslint-disable-line

  const pickLens = (id) => {
    if (id === "companion") { openComp("both"); return; }
    setLens(id); ZyMap.setLens(id);
  };
  const openComp = (view) => { setCompView(view); setScene("comp"); ZyMap.enterCompanion(view); };
  const setComp = (view) => { setCompView(view); ZyMap.setCompanionView(view); };
  const closeComp = () => { ZyMap.exitCompanion(); setScene("world"); ZyMap.setLens(lens); };

  const onCardAct = (a) => {
    if (a.go === "city") setScene("city");
    else if (a.go === "companion") openComp("both");
    else if (a.go === "companion-wish") openComp("wish");
    else if (a.go === "__refit") ZyMap.fitTo(devCoords);
    else fireToast(toastFor(a.t));
  };
  const changePalette = (p) => { setPalette(p); ZyMap.applyPalette(p); };
  const changeDensity = (d) => { setDensity(d); ZyMap.setDensity(d); };
  const locate = () => {
    if (scene === "city") window.__zymap.flyTo({ center: D.anchorNow.c, zoom: 14.5, speed: 0.9 });
    else { setLens("now"); ZyMap.setLens("now"); }
  };

  return (
    <div className="device" data-palette={palette}
      onDragOver={(e) => { e.preventDefault(); if (!dragging) setDragging(true); }}
      onDragLeave={(e) => { if (e.currentTarget === e.target) setDragging(false); }}
      onDrop={onDrop}>
      <div className="map-root">
        <div id="map" ref={mapEl} />
        <div className="grade topfade" />
        <div className="grade wash" />
        <div className="grade vignette" />
      </div>
      <div className="island" />
      <StatusBar />

      {/* TOP CHROME */}
      {scene === "world" && (
        <div className="chrome-top fade-y" key="w">
          <div className="breadcrumb">
            <span className="place">我的世界</span>
            <span className="sub">23:47 · 上海上空</span>
          </div>
          <LensRail lens={lens} onPick={pickLens} />
          <div className="develop-entry">
            <button className="dev-btn glass" onClick={() => fileRef.current && fileRef.current.click()} disabled={importing}>
              <Icon name="photo" size={15} stroke={1.6} />
              <span>{importing ? "正在显影…" : "让照片显影"}</span>
            </button>
            <button className="dev-sample glass" onClick={onSamples} disabled={importing}>示例</button>
          </div>
        </div>
      )}
      {scene === "city" && (
        <div className="chrome-top fade-y" key="c">
          <div className="breadcrumb">
            <span className="place" style={{ display: "flex", alignItems: "center", gap: 8, cursor: "pointer" }}
              onClick={() => setScene("world")}>
              <span className="glass" style={{ width: 34, height: 34, borderRadius: 11, display: "flex", alignItems: "center", justifyContent: "center", color: "var(--text)" }}>
                <Icon name="chevL" size={18} />
              </span>上海
            </span>
            <span className="sub">我的上海 · 街区级显影</span>
          </div>
        </div>
      )}

      {/* TWEAKS */}
      {scene !== "comp" && (
        <React.Fragment>
          <div className="tweaks-btn glass" onClick={() => setTweaksOpen(o => !o)}><Icon name="sliders" size={18} /></div>
          <Tweaks open={tweaksOpen} palette={palette} density={density} setPalette={changePalette} setDensity={changeDensity} />
        </React.Fragment>
      )}

      {/* FABs */}
      {scene !== "comp" && (
        <div className="fab-col">
          <div className="fab glass anchor" onClick={locate} title="此刻锚点"><Icon name="locate" size={20} /></div>
          <div className="fab glass" onClick={() => openComp("both")} title="同行"><Icon name="people" size={20} /></div>
        </div>
      )}

      {/* BOTTOM */}
      {scene === "world" && <Narrative idx={cardIdx} setIdx={setCardIdx} onAct={onCardAct} cards={cards} />}
      {scene === "city" && (
        <div className="narr glass" style={{ paddingBottom: 14 }}>
          <div className="kicker"><span className="dot" />附近回声</div>
          <div className="line" style={{ fontSize: 17 }}>
            轻点任意<em>光点</em>或<em>锚点</em>，让那处记忆浮现。<br />
            <span style={{ fontSize: 13.5, color: "var(--text-dim)" }}>这里和你的过去、未来有什么关系。</span>
          </div>
        </div>
      )}
      {scene === "comp" && <Companion view={compView} setView={setComp} onClose={closeComp} />}

      <PlaceSheet id={placeId} onClose={() => setPlaceId(null)} />
      <Toast msg={toast} />

      <input ref={fileRef} type="file" accept="image/*" multiple style={{ display: "none" }} onChange={onPickFiles} />
      {dragging && (
        <div className="dropzone" onDragOver={(e) => e.preventDefault()} onDrop={onDrop}>
          <div className="dz-inner glass"><Icon name="photo" size={26} stroke={1.4} /><span>松手 · 让它们显影</span></div>
        </div>
      )}
      <div className="home-ind" />
    </div>
  );
}

function toastFor(t) {
  const m = {
    "收为道标": "已收为道标 · 它开始在你的地图边缘发出微光",
    "让它显影": "等你真的到达那里，它会从暗处亮起来",
    "暂时沉下去": "好 · 它不会消失，只是先安静一会儿",
    "收起": "卡片收起 · 只剩一张属于你的地图",
  };
  return m[t] || ("好 · " + t);
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
