/* ============================================================
   HOME — Pixel office building (image) with room hotspots
   window.CityMap
   - Background: assets/office-building.png (white bg removed)
   - Each room: hover -> glow + label lights up -> click to enter
   - Per-room ambient animations (graphs, neon, particles)
   ============================================================ */
(function () {
  const { useState } = React;
  const { useT, Icon, GLYPH } = window.UI;

  // room hotspot polygons + label metric config (in % of building image)
  const ROOMS = [
    { key: "tiktok", en: "TikTok Live Office", th: "ออฟฟิศไลฟ์ติ๊กต็อก", subEn: "Live viewers", subTh: "ผู้ชมไลฟ์",
      c: "tiktok-pink", ic: "play", viz: "bars", val: "1,358", live: true,
      label: [24, 16], pts: [[2,17],[42,1],[52,6],[50,35],[4,40]] },
    { key: "facebook", en: "Facebook Office", th: "สำนักงานเฟซบุ๊ก", subEn: "Engagement today", subTh: "เอนเกจวันนี้",
      c: "fb", ic: "chat", viz: "line", val: "5,164",
      label: [76, 16], pts: [[52,6],[62,1],[98,17],[98,40],[51,35]] },
    { key: "finance", en: "Finance Office", th: "ห้องบัญชีการเงิน", subEn: "Profit today", subTh: "กำไรวันนี้",
      c: "ok", ic: "coin", viz: "bars", val: "฿23.1k",
      label: [50, 76], pts: [[30,61],[70,61],[83,98],[17,98]] },
    { key: "hr", en: "HR Cute Office", th: "ฝ่ายบุคคล", subEn: "Team morale", subTh: "ขวัญกำลังใจ",
      c: "ig", ic: "heart", viz: "hearts", val: "94%",
      label: [23, 48], pts: [[2,38],[49,34],[50,61],[3,66]] },
    { key: "stock", en: "Stock Warehouse", th: "คลังสินค้า", subEn: "Packed today", subTh: "แพ็ควันนี้",
      c: "shopee", ic: "box", viz: "bar", val: "147",
      label: [77, 49], pts: [[51,34],[98,39],[98,66],[50,61]] },
  ];
  const LOBBY = { label: [50, 91], pts: [[17,61],[83,61],[98,98],[2,98]] };

  const ptStr = (pts) => pts.map((p) => p.join(",")).join(" ");
  const cv = (name) => `var(--${name})`;

  // mini animated metric viz shown inside each label pill
  function Viz({ type, color }) {
    if (type === "line") {
      return (
        <svg className="rc-line" viewBox="0 0 60 22" preserveAspectRatio="none">
          <polyline points="0,17 10,11 20,14 30,6 40,10 50,3 60,8" fill="none" stroke={color} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" />
        </svg>
      );
    }
    if (type === "hearts") {
      return <span className="rc-hearts"><i style={{ color }}>♥</i><i style={{ color }}>♥</i></span>;
    }
    if (type === "bar") {
      return <span className="rc-pbar"><i style={{ background: color }} /></span>;
    }
    return <span className="rc-bars">{[0, 1, 2, 3, 4].map((i) => <i key={i} style={{ background: color, animationDelay: i * 0.15 + "s" }} />)}</span>;
  }

  // ---------- encouragement mascot ----------
  const PEP = [
    ["You've got this! 🐾", "สู้ๆ นะ วันนี้ทำได้แน่! 🐾"],
    ["Sales looking great!", "ยอดขายกำลังไปได้สวยเลย!"],
    ["Take a water break 💧", "พักดื่มน้ำสักหน่อยมั้ย 💧"],
    ["Best team ever!", "ทีมเราเก่งที่สุด!"],
    ["One task at a time 💪", "ปิดงานทีละนิด เดี๋ยวก็เสร็จ 💪"],
    ["Don't forget restock!", "ของใกล้หมด อย่าลืมเติมนะ"],
    ["Smile — customers love it 😺", "ยิ้มไว้ ลูกค้ารักเลย 😺"],
    ["Proud of you today!", "วันนี้เก่งมากเลย ภูมิใจนะ!"],
  ];
  function Mascot() {
    const t = useT();
    const [i, setI] = useState(0);
    const [bump, setBump] = useState(false);
    const [on, setOn] = useState(() => { try { return localStorage.getItem("pg_mascot") !== "0"; } catch (e) { return true; } });
    React.useEffect(() => {
      if (!on) return;
      const id = setInterval(() => setI((n) => (n + 1) % PEP.length), 4800);
      return () => clearInterval(id);
    }, [on]);
    React.useEffect(() => { try { localStorage.setItem("pg_mascot", on ? "1" : "0"); } catch (e) {} }, [on]);
    const poke = () => { setI((n) => (n + 1) % PEP.length); setBump(true); setTimeout(() => setBump(false), 420); };
    if (!on) {
      return (
        <button className="mascot-reopen" onClick={() => setOn(true)} title={t("Show buddy", "เปิดผู้ช่วยให้กำลังใจ")} aria-label="show buddy">
          <span className="mph-face"><span className="mph-eye" /><span className="mph-eye" /></span>
        </button>
      );
    }
    return (
      <div className="mascot">
        <button className="mascot-close" onClick={() => setOn(false)} title={t("Hide", "ซ่อน")} aria-label="hide buddy"><Icon name="chev" size={13} /></button>
        <div className="mascot-bubble" key={i}>{t(PEP[i][0], PEP[i][1])}</div>
        <button className={"mascot-ph" + (bump ? " bump" : "")} onClick={poke} aria-label="encourage">
          <span className="mph-face">
            <span className="mph-eye" /><span className="mph-eye" />
          </span>
          <span className="mph-tag">PNG</span>
        </button>
      </div>
    );
  }

  // Browser-generated ambience: no external audio files and no autoplay.
  function OfficeAmbience() {
    const t = useT();
    const [on, setOn] = useState(false);
    const audio = React.useRef(null);

    const stop = () => {
      const a = audio.current;
      if (!a) return;
      a.timers.forEach(clearInterval);
      try { a.ctx.close(); } catch (e) {}
      audio.current = null;
      setOn(false);
    };

    const start = () => {
      const AudioCtx = window.AudioContext || window.webkitAudioContext;
      if (!AudioCtx) return;
      const ctx = new AudioCtx();
      const master = ctx.createGain();
      master.gain.value = 0.22;
      master.connect(ctx.destination);

      // Soft air-conditioning / office-room tone.
      const hum = ctx.createOscillator();
      const humGain = ctx.createGain();
      hum.type = "sine"; hum.frequency.value = 74; humGain.gain.value = 0.025;
      hum.connect(humGain).connect(master); hum.start();
      const buffer = ctx.createBuffer(1, ctx.sampleRate * 2, ctx.sampleRate);
      const data = buffer.getChannelData(0);
      for (let i = 0; i < data.length; i++) data[i] = (Math.random() * 2 - 1) * 0.22;
      const air = ctx.createBufferSource();
      const filter = ctx.createBiquadFilter();
      const airGain = ctx.createGain();
      filter.type = "lowpass"; filter.frequency.value = 520; airGain.gain.value = 0.035;
      air.buffer = buffer; air.loop = true; air.connect(filter).connect(airGain).connect(master); air.start();

      const click = (time, freq, gain, length) => {
        const osc = ctx.createOscillator(); const g = ctx.createGain();
        osc.type = "square"; osc.frequency.value = freq;
        g.gain.setValueAtTime(gain, time); g.gain.exponentialRampToValueAtTime(0.0001, time + length);
        osc.connect(g).connect(master); osc.start(time); osc.stop(time + length + 0.01);
      };
      const typeBurst = () => {
        if (Math.random() < 0.32) return;
        const count = 2 + Math.floor(Math.random() * 5); const now = ctx.currentTime;
        for (let i = 0; i < count; i++) click(now + i * (0.045 + Math.random() * 0.035), 620 + Math.random() * 420, 0.018, 0.022);
      };
      const elevator = () => {
        const now = ctx.currentTime;
        [659, 988].forEach((freq, i) => {
          const osc = ctx.createOscillator(); const g = ctx.createGain();
          osc.type = "sine"; osc.frequency.value = freq;
          g.gain.setValueAtTime(0.0001, now + i * 0.16);
          g.gain.exponentialRampToValueAtTime(0.11, now + i * 0.16 + 0.02);
          g.gain.exponentialRampToValueAtTime(0.0001, now + i * 0.16 + 0.75);
          osc.connect(g).connect(master); osc.start(now + i * 0.16); osc.stop(now + i * 0.16 + 0.8);
        });
      };
      const timers = [setInterval(typeBurst, 720), setInterval(elevator, 26000)];
      setTimeout(() => { if (audio.current && audio.current.ctx === ctx) elevator(); }, 2800);
      audio.current = { ctx, timers };
      setOn(true);
    };

    React.useEffect(() => () => {
      const a = audio.current;
      if (a) { a.timers.forEach(clearInterval); try { a.ctx.close(); } catch (e) {} }
    }, []);

    return (
      <button className={"sound-ctrl" + (on ? " is-on" : "")} onClick={on ? stop : start}
        title={t(on ? "Mute office ambience" : "Play office ambience", on ? "ปิดเสียงออฟฟิศ" : "เปิดเสียงออฟฟิศ")}
        aria-pressed={on}>
        <span className="sound-icon">{on ? "🔊" : "🔇"}</span>
        <span>{t(on ? "Office sound on" : "Office sound", on ? "เปิดเสียงแล้ว" : "เสียงออฟฟิศ")}</span>
      </button>
    );
  }

  function CityMap({ onEnter }) {
    const t = useT();
    const D = window.DATA;
    const [hover, setHover] = useState(null);
    const [collapsed, setCollapsed] = useState({});
    const toggle = (k) => setCollapsed((c) => ({ ...c, [k]: !c[k] }));
    const byKey = Object.fromEntries(D.buildings.map((b) => [b.key, b]));

    // -------- pan + zoom --------
    const stageRef = React.useRef(null);
    const [view, setView] = useState({ s: 1, x: 0, y: 0 });
    const drag = React.useRef({ on: false, sx: 0, sy: 0, ox: 0, oy: 0, moved: false });

    const clampView = (v) => {
      const s = Math.min(2.8, Math.max(1, v.s));
      const el = stageRef.current;
      let mx = 0, my = 0;
      if (el) { mx = (el.clientWidth * (s - 1)) / 2 + 80; my = (el.clientHeight * (s - 1)) / 2 + 80; }
      return { s, x: Math.max(-mx, Math.min(mx, v.x)), y: Math.max(-my, Math.min(my, v.y)) };
    };
    const zoomBy = (factor, cx, cy) => {
      setView((v) => {
        const ns = Math.min(2.8, Math.max(1, v.s * factor));
        if (ns === v.s) return v;
        const el = stageRef.current;
        let px = 0, py = 0;
        if (el && cx != null) { const r = el.getBoundingClientRect(); px = cx - r.left - r.width / 2; py = cy - r.top - r.height / 2; }
        const k = ns / v.s;
        const nx = px - k * (px - v.x);
        const ny = py - k * (py - v.y);
        return ns <= 1 ? { s: 1, x: 0, y: 0 } : clampView({ s: ns, x: nx, y: ny });
      });
    };
    const reset = () => setView({ s: 1, x: 0, y: 0 });

    React.useEffect(() => {
      const el = stageRef.current; if (!el) return;
      const onWheel = (e) => { e.preventDefault(); zoomBy(e.deltaY < 0 ? 1.12 : 1 / 1.12, e.clientX, e.clientY); };
      el.addEventListener("wheel", onWheel, { passive: false });
      return () => el.removeEventListener("wheel", onWheel);
    }, []);

    const onDown = (e) => {
      drag.current = { on: true, sx: e.clientX, sy: e.clientY, ox: view.x, oy: view.y, moved: false };
    };
    const onMove = (e) => {
      const d = drag.current; if (!d.on) return;
      const dx = e.clientX - d.sx, dy = e.clientY - d.sy;
      if (Math.abs(dx) + Math.abs(dy) > 4) d.moved = true;
      setView((v) => clampView({ s: v.s, x: d.ox + dx, y: d.oy + dy }));
    };
    const onUp = () => { drag.current.on = false; };
    const guardEnter = (k) => { if (!drag.current.moved) onEnter(k); };

    return (
      <div className="city-screen img-home fade-in">
        {/* isometric theme-aware city backdrop (faint, subtle parallax) */}
        <div className="iso-bg">
          <div className="iso-sky" />
          <div className="iso-parallax" style={{ transform: `translate(${view.x * 0.22}px, ${view.y * 0.22}px) scale(${1 + (view.s - 1) * 0.16})` }}>
            <img className="city-bg-img dark-only" src="assets/city-bg-night.png" alt="" draggable="false" />
            <img className="city-bg-img light-only" src="assets/city-bg-day.png" alt="" draggable="false" />
          </div>
          <div className="iso-fade" />
        </div>

        {/* pan/zoom stage */}
        <div
          ref={stageRef}
          className={"city-stage" + (drag.current.on ? " grabbing" : "")}
          onPointerDown={onDown} onPointerMove={onMove} onPointerUp={onUp} onPointerLeave={onUp}
        >
          <div className="city-stage-inner" style={{ transform: `translate(${view.x}px, ${view.y}px) scale(${view.s})` }}>
            <div className={"img-scene" + (hover ? " has-hover" : "")}>
              <img className="img-bld dark-only" src="assets/office-building-cat-office.png" alt="All Good Office building" draggable="false" />
              <img className="img-bld light-only" src="assets/office-building-cat-office.png" alt="All Good Office building" draggable="false" />

              <svg className="img-hot" viewBox="0 0 100 100" preserveAspectRatio="none">
                {ROOMS.map((r) => (
                  <polygon key={r.key} className="hot-poly" points={ptStr(r.pts)}
                    onMouseEnter={() => setHover(r.key)}
                    onMouseLeave={() => setHover((h) => (h === r.key ? null : h))}
                    onClick={() => guardEnter(r.key)} />
                ))}
              </svg>

              {ROOMS.map((r) => {
                const cx = r.pts.reduce((a, p) => a + p[0], 0) / r.pts.length;
                const cy = r.pts.reduce((a, p) => a + p[1], 0) / r.pts.length;
                return (
                  <span key={r.key} className={"room-dot" + (hover === r.key ? " on" : "")}
                    style={{ left: cx + "%", top: cy + "%", "--rc": cv(r.c) }}
                    onMouseEnter={() => setHover(r.key)}
                    onMouseLeave={() => setHover((h) => (h === r.key ? null : h))}
                    onClick={() => guardEnter(r.key)} />
                );
              })}

              {ROOMS.map((r) => {
                const b = byKey[r.key];
                const on = hover === r.key;
                return (
                  <div key={r.key} className={"room-chip" + (on ? " on" : "")}
                    style={{ left: r.label[0] + "%", top: r.label[1] + "%", "--rc": cv(r.c) }}
                    onMouseEnter={() => setHover(r.key)}
                    onMouseLeave={() => setHover((h) => (h === r.key ? null : h))}
                    onClick={() => guardEnter(r.key)}>
                    <div className="rc-row">
                      <span className="rc-ico"><Icon name={r.ic} size={15} /></span>
                      <span className="rc-viz"><Viz type={r.viz} color="var(--rc)" /></span>
                      {r.live && <span className="rc-live">LIVE</span>}
                      <span className="rc-val">{r.val}</span>
                    </div>
                    <div className="rc-more">
                      <div className="rc-more-in">
                        <div className="rc-name">{r.en}</div>
                        <div className="rc-sub">{r.th} · {t(r.subEn, r.subTh)}</div>
                        <span className="rc-enter"><Icon name="chev" size={13} /> {t("Enter office", "เข้าห้อง")} →</span>
                      </div>
                    </div>
                    {b && b.alerts > 0 && <span className={"rc-badge " + b.alertKind}>{b.alerts}</span>}
                  </div>
                );
              })}

              <div className="room-tag lobby-tag" style={{ left: LOBBY.label[0] + "%", top: LOBBY.label[1] + "%" }}>
                <span className="rt-ico"><Icon name="map" size={14} /></span>
                <span className="rt-name">{t("Lobby", "ล็อบบี้")}</span>
              </div>
            </div>
          </div>
        </div>

        {/* zoom controls */}
        <div className="zoom-ctrl">
          <button onClick={() => zoomBy(1.25)} aria-label="zoom in"><Icon name="plus" size={16} /></button>
          <span className="zoom-val">{Math.round(view.s * 100)}%</span>
          <button onClick={() => zoomBy(1 / 1.25)} aria-label="zoom out"><Icon name="minus" size={16} /></button>
          <button onClick={reset} aria-label="reset" className="zoom-reset"><Icon name="target" size={15} /></button>
        </div>

        {/* encouragement mascot */}
        <Mascot />

        {/* opt-in office ambience (Chrome requires a user click before audio) */}
        <OfficeAmbience />

        {/* ---- alerts panel (only one kept) ---- */}
        <div className={"city-panel rt" + (collapsed.alerts ? " is-collapsed" : "")}>
          <div className="cp-bar" onClick={() => toggle("alerts")}>
            <Icon name="warn" size={15} />
            <h4>{t("Live Alerts", "การแจ้งเตือน")}</h4>
            <span className="cp-count">{D.alerts.length}</span>
            <button className="cp-collapse" aria-label="toggle" onClick={(e) => { e.stopPropagation(); toggle("alerts"); }}>
              <Icon name="chev" size={15} />
            </button>
          </div>
          <div className="cp-collapsible">
            <div className="feed">
              {D.alerts.slice(0, 6).map((a, i) => {
                const b = byKey[a.b];
                return (
                  <div key={i} className="feed-item" onClick={() => onEnter(a.b)}>
                    <div className="feed-ico" style={{ background: "var(--" + b.colorRaw + ")22", color: "var(--" + b.colorRaw + ")", boxShadow: "inset 0 0 0 1px var(--" + b.colorRaw + ")55" }}>
                      <Icon name={GLYPH[b.glyph]} size={16} />
                    </div>
                    <div className="feed-body">
                      <div className="feed-en">{a.en}</div>
                      <div className="feed-th">{a.th}</div>
                      <div className="feed-time">{b.en} · {a.t}</div>
                    </div>
                    <span className={"sdot " + a.kind} style={{ marginTop: 5 }} />
                  </div>
                );
              })}
            </div>
          </div>
        </div>

        <div className="city-hint">
          <Icon name="map" size={14} />
          {t("Scroll to zoom · drag to move · click a room to enter", "เลื่อนเพื่อซูม · ลากเพื่อเลื่อน · คลิกห้องเพื่อเข้าทำงาน")}
        </div>
      </div>
    );
  }

  window.CityMap = CityMap;
})();
