/* Location Hunter — retro arcade map hunt */
const { useState, useEffect, useRef, useCallback, useMemo } = React;

// ------- Haversine distance (meters) -------
function distMeters(a, b) {
  const R = 6371000;
  const toRad = (d) => (d * Math.PI) / 180;
  const dLat = toRad(b.lat - a.lat);
  const dLng = toRad(b.lng - a.lng);
  const la1 = toRad(a.lat);
  const la2 = toRad(b.lat);
  const h =
    Math.sin(dLat / 2) ** 2 +
    Math.cos(la1) * Math.cos(la2) * Math.sin(dLng / 2) ** 2;
  return 2 * R * Math.asin(Math.sqrt(h));
}

// ------- Pixel pin SVG -------
const PixelPin = ({ size = 42 }) => (
  <svg
    width={size}
    height={size * (56 / 42)}
    viewBox="0 0 14 19"
    shapeRendering="crispEdges"
  >
    {/* chunky pixel pin */}
    <g fill="#111217">
      <rect x="4" y="0" width="6" height="1" />
      <rect x="2" y="1" width="10" height="1" />
      <rect x="1" y="2" width="12" height="6" />
      <rect x="2" y="8" width="10" height="1" />
      <rect x="3" y="9" width="8" height="1" />
      <rect x="4" y="10" width="6" height="1" />
      <rect x="5" y="11" width="4" height="1" />
      <rect x="6" y="12" width="2" height="1" />
    </g>
    <g fill="#ff3b5c">
      <rect x="2" y="2" width="10" height="6" />
    </g>
    <g fill="#ffd23f">
      <rect x="5" y="3" width="4" height="3" />
    </g>
    <g fill="#111217">
      <rect x="6" y="4" width="2" height="1" />
    </g>
  </svg>
);

// ------- Start Screen -------
function StartScreen({ onStart, tweaks }) {
  return (
    <div
      className="dot-bg"
      style={{
        position: "absolute",
        inset: 0,
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
        padding: 24,
      }}
    >
      <div className="floaters" aria-hidden="true">
        {Array.from({ length: 10 }).map((_, i) => (
          <div
            key={i}
            className="floater"
            style={{
              left: `${(i * 9 + 7) % 100}%`,
              animationDelay: `${(i * 0.6) % 6}s`,
              fontSize: `${Math.max(16 + (i % 3) * 6, 15) / 16}rem`,
            }}
          >
            {["♥", "★", "✦", "♦", "♠"][i % 5]}
          </div>
        ))}
      </div>

      <div
        style={{
          position: "relative",
          zIndex: 2,
          width: "min(640px, 100%)",
          display: "flex",
          flexDirection: "column",
          alignItems: "center",
          gap: 28,
        }}
      >
        {/* Arcade cabinet header */}
        <div
          className="pbox"
          style={{
            padding: 0,
            width: "100%",
            background: "#111217",
            borderColor: "#111217",
          }}
        >
          <div
            style={{
              padding: "18px 20px",
              background: "var(--accent)",
              borderBottom: "3px solid #111217",
            }}
          >
            <div
              className="pixel"
              style={{ fontSize: "0.9375rem", color: "#fff", letterSpacing: 4 }}
            >
              ▸ 按下開始 ◂
            </div>
          </div>
          <div
            style={{
              padding: "28px 20px 24px",
              textAlign: "center",
              background: "var(--paper)",
            }}
          >
            <div
              className="pixel"
              style={{
                fontSize: "1.625rem",
                lineHeight: 1.2,
                color: "var(--ink)",
              }}
            >
              <span style={{ color: "var(--accent)" }}>♥</span>{" "}
              {tweaks.titleText}{" "}
              <span style={{ color: "var(--accent)" }}>♥</span>
            </div>
            <div
              className="pixel"
              style={{
                fontSize: "0.9375rem",
                marginTop: 14,
                color: "var(--ink)",
                opacity: 0.8,
              }}
            >
              {tweaks.subtitleText}
            </div>
          </div>
        </div>

        {/* Instructions */}
        <div
          className="pbox"
          style={{
            padding: "16px 18px",
            width: "100%",
            background: "var(--paper-2)",
          }}
        >
          <div className="tt" style={{ marginBottom: 10 }}>
            玩法說明
          </div>
          <div style={{ fontSize: "1.25rem", lineHeight: 1.35 }}>
            <div>► 閱讀提示，找出地點。</div>
            <div>► 拖動地圖，讓圖釘落在正確位置。</div>
            <div>
              ► 點擊 <b>確認</b> 檢查你的答案。
            </div>
            <div>► 完成全部 6 個回合即可打開保險箱。</div>
          </div>
        </div>

        <button
          className="btn primary"
          onClick={onStart}
          style={{ fontSize: "0.9375rem", padding: "18px 28px" }}
        >
          ▶ {tweaks.startCta}
        </button>

        <div className="tt" style={{ opacity: 0.6 }}>
          © 🐑🐑🐑 · 以 ♥ 製作 · 版本 1.0
        </div>
      </div>
    </div>
  );
}

// ------- End Screen -------
function EndScreen({ solved, tweaks, onReplay }) {
  const total = tweaks.rounds.length;
  const count = solved.filter(Boolean).length;

  return (
    <div
      className="dot-bg"
      style={{
        position: "absolute",
        inset: 0,
        overflow: "auto",
        padding: 24,
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
      }}
    >
      <div
        style={{
          width: "min(640px, 100%)",
          display: "flex",
          flexDirection: "column",
          gap: 20,
        }}
      >
        <div
          className="pbox"
          style={{ background: "var(--accent-2)", padding: 0 }}
        >
          <div
            style={{
              padding: "16px 20px",
              background: "var(--ink)",
              color: "var(--paper)",
            }}
          >
            <div className="pixel" style={{ fontSize: "0.9375rem" }}>
              ◆ 遊戲完成 ◆
            </div>
          </div>
          <div style={{ padding: "22px 20px", textAlign: "center" }}>
            <div
              className="pixel"
              style={{ fontSize: "1.375rem", lineHeight: 1.2 }}
            >
              {tweaks.endTitle}
            </div>
            <div className="tt" style={{ marginTop: 10 }}>
              得分 · {count} / {total}
            </div>
          </div>
        </div>

        <div
          className="pbox"
          style={{ padding: 28, background: "var(--paper-2)" }}
        >
          <div
            className="pixel"
            style={{
              fontSize: "1.125rem",
              lineHeight: 1.4,
              textAlign: "center",
              whiteSpace: "pre-line",
            }}
          >
            {tweaks.endMessage}
          </div>
        </div>

        <div
          style={{
            display: "flex",
            gap: 12,
            justifyContent: "center",
            flexWrap: "wrap",
          }}
        >
          <button className="btn ghost" onClick={onReplay}>
            ↺ 再玩一次
          </button>
        </div>
      </div>
    </div>
  );
}

// ------- Challenge Screen (map) -------
function ChallengeScreen({ round, idx, total, onResult, tweaks }) {
  const mapEl = useRef(null);
  const mapRef = useRef(null);
  const [hintOpen, setHintOpen] = useState(true);
  const [result, setResult] = useState(null); // {correct, dist}
  const [attempts, setAttempts] = useState(0);
  const [bounce, setBounce] = useState(false);
  const [rewardOpen, setRewardOpen] = useState(false);
  const pinRef = useRef(null);
  const ansMarkerRef = useRef(null);

  // Initialize map (once per round)
  useEffect(() => {
    if (!mapEl.current) return;
    // default center — Berlin
    const map = L.map(mapEl.current, {
      center: [52.52, 13.405],
      zoom: 11,
      zoomControl: true,
      attributionControl: true,
      worldCopyJump: true,
    });
    mapRef.current = map;

    L.tileLayer(
      "https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",
      {
        maxZoom: 19,
        subdomains: ["a", "b", "c", "d"],
        attribution: "© OpenStreetMap © CARTO",
      },
    ).addTo(map);

    return () => {
      map.remove();
      mapRef.current = null;
    };
  }, [idx]);

  // Confetti on correct
  const fireConfetti = () => {
    const root = document.getElementById("root");
    const colors = ["#ff3b5c", "#ffd23f", "#2ec4b6", "#3a86ff", "#111217"];
    for (let i = 0; i < 40; i++) {
      const c = document.createElement("div");
      c.className = "confetti";
      c.style.background = colors[i % colors.length];
      c.style.left = 48 + Math.random() * 4 + "%";
      c.style.top = "50%";
      c.style.transform = `rotate(${Math.random() * 360}deg)`;
      root.appendChild(c);
      const angle = Math.random() * Math.PI * 2;
      const dist = 180 + Math.random() * 260;
      const dx = Math.cos(angle) * dist;
      const dy = Math.sin(angle) * dist - 100;
      c.animate(
        [
          { transform: c.style.transform, opacity: 1 },
          {
            transform: `translate(${dx}px, ${dy}px) rotate(${Math.random() * 720}deg)`,
            opacity: 0,
          },
        ],
        {
          duration: 1100 + Math.random() * 400,
          easing: "cubic-bezier(.2,.8,.2,1)",
        },
      ).onfinish = () => c.remove();
    }
  };

  const handleConfirm = () => {
    if (!mapRef.current) return;
    const c = mapRef.current.getCenter();
    const guess = { lat: c.lat, lng: c.lng };
    const target = { lat: round.lat, lng: round.lng };
    const d = distMeters(guess, target);
    const correct = d <= tweaks.toleranceMeters;
    setResult({ correct, dist: d });
    setAttempts((a) => a + 1);
    setBounce(true);
    setTimeout(() => setBounce(false), 650);

    if (correct) {
      // drop an answer marker + pan
      if (ansMarkerRef.current) ansMarkerRef.current.remove();
      const icon = L.divIcon({
        className: "ans-marker-wrap",
        html: '<div class="ans-marker"></div>',
        iconSize: [22, 22],
        iconAnchor: [11, 11],
      });
      ansMarkerRef.current = L.marker([round.lat, round.lng], { icon }).addTo(
        mapRef.current,
      );
      fireConfetti();
      setTimeout(() => {
        setResult(null);
        setRewardOpen(true);
      }, 1400);
    } else {
      setTimeout(() => setResult(null), 1400);
    }
  };

  const closeReward = () => {
    setRewardOpen(false);
    onResult(true);
  };

  const progressPct = (idx / total) * 100;

  return (
    <div style={{ position: "absolute", inset: 0 }}>
      {/* Map */}
      <div ref={mapEl} style={{ position: "absolute", inset: 0 }} />

      {/* Center pin */}
      <div
        className={"center-pin" + (bounce ? " bounce" : "")}
        aria-hidden="true"
      >
        <PixelPin size={44} />
      </div>

      {/* HUD */}
      <div className="hud">
        <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
          <div className="hud-chip">
            回合 {idx + 1}/{total}
          </div>
          <div
            className="hud-chip"
            style={{ background: "var(--accent-2)", color: "var(--ink)" }}
          >
            嘗試次數 · {attempts}
          </div>
        </div>
        <div
          style={{
            display: "flex",
            flexDirection: "column",
            gap: 8,
            alignItems: "flex-end",
          }}
        >
          <button
            className="btn teal"
            onClick={() => setHintOpen(true)}
            style={{ fontSize: "0.9375rem", padding: "15px 14px" }}
          >
            ? 提示
          </button>
        </div>
      </div>

      {/* Progress bar bottom */}
      <div
        style={{
          position: "absolute",
          left: 12,
          right: 12,
          bottom: 76,
          zIndex: 500,
          height: 18,
          background: "var(--paper)",
          border: "3px solid var(--ink)",
          boxShadow: "3px 3px 0 rgba(0,0,0,0.4)",
        }}
      >
        <div
          style={{
            height: "100%",
            width: progressPct + "%",
            background: "var(--accent-3)",
            transition: "width 300ms ease",
          }}
        />
      </div>

      {/* Confirm bar */}
      <div
        style={{
          position: "absolute",
          left: 12,
          right: 12,
          bottom: 12,
          zIndex: 500,
          display: "flex",
          gap: 10,
          alignItems: "center",
          justifyContent: "center",
        }}
      >
        <div
          className="hud-chip"
          style={{
            background: "var(--paper)",
            color: "var(--ink)",
            flex: 1,
            textAlign: "center",
          }}
        >
          拖動地圖 · 圖釘為你的答案
        </div>
        <button
          className="btn primary"
          onClick={handleConfirm}
          style={{ fontSize: "0.9375rem", padding: "14px 22px" }}
        >
          ✓ 確認
        </button>
      </div>

      {/* Hint modal */}
      {hintOpen && (
        <div className="modal-backdrop" onClick={() => setHintOpen(false)}>
          <div className="modal" onClick={(e) => e.stopPropagation()}>
            <div className="modal-title">
              <span>
                提示 · 回合 {idx + 1}/{total}
              </span>
              <button
                className="x-btn"
                onClick={() => setHintOpen(false)}
                aria-label="關閉"
              >
                X
              </button>
            </div>
            <div className="modal-body">
              {round.image && (
                <div
                  className="hint-img-ph"
                  style={{
                    backgroundImage: `url(${round.image})`,
                    backgroundSize: "cover",
                    backgroundPosition: "center",
                  }}
                />
              )}
              {!round.image && round.showImagePlaceholder && (
                <div className="hint-img-ph">[ 提示圖片預留位置 ]</div>
              )}
              <div style={{ whiteSpace: "pre-line" }}>{round.hint}</div>
              <div
                style={{
                  marginTop: 18,
                  display: "flex",
                  justifyContent: "flex-end",
                }}
              >
                <button className="btn" onClick={() => setHintOpen(false)}>
                  知道了
                </button>
              </div>
            </div>
          </div>
        </div>
      )}

      {/* Reward modal */}
      {rewardOpen && (
        <div className="modal-backdrop">
          <div
            className="modal"
            style={{ width: "min(640px, 100%)" }}
            onClick={(e) => e.stopPropagation()}
          >
            <div className="modal-title">
              <span>★ 線索解鎖 ★</span>
              <button className="x-btn" onClick={closeReward} aria-label="關閉">
                X
              </button>
            </div>
            <div className="modal-body">
              {round.video && (
                <div
                  style={{
                    position: "relative",
                    paddingBottom: "75%",
                    height: 0,
                    marginBottom: 16,
                    border: "3px solid var(--ink)",
                    background: "#000",
                  }}
                >
                  <iframe
                    src={ytEmbed(round.video)}
                    style={{
                      position: "absolute",
                      inset: 0,
                      width: "100%",
                      height: "100%",
                      border: 0,
                    }}
                    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
                    allowFullScreen
                    title="reward"
                  />
                </div>
              )}
              <div
                className="pixel"
                style={{
                  fontSize: "0.9375rem",
                  lineHeight: 1.45,
                  whiteSpace: "pre-line",
                  textAlign: "center",
                  padding: "6px 4px",
                }}
              >
                {round.rewardText || ""}
              </div>
              <div
                style={{
                  marginTop: 18,
                  display: "flex",
                  justifyContent: "flex-end",
                }}
              >
                <button className="btn primary" onClick={closeReward}>
                  {idx + 1 >= total ? "完成 ▶" : "下一回合 ▶"}
                </button>
              </div>
            </div>
          </div>
        </div>
      )}

      {/* Flash result */}
      {result && (
        <div className={"flash " + (result.correct ? "good" : "bad")}>
          <div className="card">
            {result.correct ? (
              <>
                ✓ 正確！
                <div
                  style={{
                    fontSize: "0.9375rem",
                    marginTop: 10,
                    fontFamily: "Press Start 2P",
                    opacity: 0.8,
                  }}
                >
                  距離 {Math.round(result.dist)} 米
                </div>
              </>
            ) : (
              <>
                ✗ 再試一次
                <div
                  style={{
                    fontSize: "0.9375rem",
                    marginTop: 10,
                    fontFamily: "Press Start 2P",
                  }}
                >
                  相差 {fmtDist(result.dist)}
                </div>
              </>
            )}
          </div>
        </div>
      )}
    </div>
  );
}

function fmtDist(m) {
  if (m < 1000) return Math.round(m) + " 米";
  return (m / 1000).toFixed(1) + " 公里";
}

// Convert any YouTube URL to an embed URL
function ytEmbed(url) {
  if (!url) return "";
  try {
    const u = new URL(url);
    let id = "";
    if (u.hostname.includes("youtu.be")) id = u.pathname.slice(1);
    else if (u.pathname.startsWith("/embed/")) id = u.pathname.split("/")[2];
    else if (u.pathname.startsWith("/shorts/")) id = u.pathname.split("/")[2];
    else id = u.searchParams.get("v") || "";
    id = (id || "").split(/[?&/]/)[0];
    if (!id) return url;
    return `https://www.youtube.com/embed/${id}?rel=0`;
  } catch (e) {
    return url;
  }
}

// ------- Tweaks Panel -------
function TweaksPanel({ tweaks, setTweaks, onClose }) {
  const [tab, setTab] = useState("general");

  const update = (patch) => {
    const next = { ...tweaks, ...patch };
    setTweaks(next);
    // Send only the changed keys
    window.parent &&
      window.parent.postMessage(
        { type: "__edit_mode_set_keys", edits: patch },
        "*",
      );
  };
  const updateRound = (i, patch) => {
    const rounds = tweaks.rounds.map((r, k) =>
      k === i ? { ...r, ...patch } : r,
    );
    update({ rounds });
  };

  return (
    <div className="tweak-panel">
      <h3>
        <span>◆ 設定</span>
        <button className="x-btn" onClick={onClose}>
          X
        </button>
      </h3>
      <div className="tab-strip">
        {[
          ["general", "一般"],
          ["rounds", "回合"],
          ["text", "文字"],
        ].map(([t, label]) => (
          <button
            key={t}
            className={tab === t ? "active" : ""}
            onClick={() => setTab(t)}
          >
            {label}
          </button>
        ))}
      </div>
      <div className="content">
        {tab === "general" && (
          <>
            <div className="tweak-row">
              <label>容許誤差（米）</label>
              <input
                type="number"
                value={tweaks.toleranceMeters}
                onChange={(e) =>
                  update({ toleranceMeters: Number(e.target.value) })
                }
              />
            </div>
            <div className="tweak-row">
              <label>城市／地區名稱</label>
              <input
                value={tweaks.cityName}
                onChange={(e) => update({ cityName: e.target.value })}
              />
            </div>
          </>
        )}
        {tab === "text" && (
          <>
            <div className="tweak-row">
              <label>標題</label>
              <input
                value={tweaks.titleText}
                onChange={(e) => update({ titleText: e.target.value })}
              />
            </div>
            <div className="tweak-row">
              <label>副標題</label>
              <input
                value={tweaks.subtitleText}
                onChange={(e) => update({ subtitleText: e.target.value })}
              />
            </div>
            <div className="tweak-row">
              <label>開始按鈕</label>
              <input
                value={tweaks.startCta}
                onChange={(e) => update({ startCta: e.target.value })}
              />
            </div>
            <div className="tweak-row">
              <label>結束標題</label>
              <input
                value={tweaks.endTitle}
                onChange={(e) => update({ endTitle: e.target.value })}
              />
            </div>
            <div className="tweak-row">
              <label>結束訊息</label>
              <textarea
                value={tweaks.endMessage}
                onChange={(e) => update({ endMessage: e.target.value })}
              />
            </div>
          </>
        )}
        {tab === "rounds" && (
          <>
            {tweaks.rounds.map((r, i) => (
              <div
                key={i}
                className="pbox"
                style={{
                  padding: 10,
                  marginBottom: 12,
                  background: "var(--paper-2)",
                }}
              >
                <div className="tt" style={{ marginBottom: 6 }}>
                  回合 {i + 1}
                </div>
                <div className="tweak-row">
                  <label>提示文字</label>
                  <textarea
                    value={r.hint}
                    onChange={(e) => updateRound(i, { hint: e.target.value })}
                  />
                </div>
                <div
                  style={{
                    display: "grid",
                    gridTemplateColumns: "1fr 1fr",
                    gap: 8,
                  }}
                >
                  <div className="tweak-row">
                    <label>緯度</label>
                    <input
                      type="number"
                      step="0.0001"
                      value={r.lat}
                      onChange={(e) =>
                        updateRound(i, { lat: Number(e.target.value) })
                      }
                    />
                  </div>
                  <div className="tweak-row">
                    <label>經度</label>
                    <input
                      type="number"
                      step="0.0001"
                      value={r.lng}
                      onChange={(e) =>
                        updateRound(i, { lng: Number(e.target.value) })
                      }
                    />
                  </div>
                </div>
                <div className="tweak-row">
                  <label>地點標籤</label>
                  <input
                    value={r.spot}
                    onChange={(e) => updateRound(i, { spot: e.target.value })}
                  />
                </div>
                <div className="tweak-row">
                  <label>YouTube 影片網址</label>
                  <input
                    value={r.video || ""}
                    onChange={(e) => updateRound(i, { video: e.target.value })}
                  />
                </div>
                <div className="tweak-row">
                  <label>獎勵文字（顯示於影片下方）</label>
                  <textarea
                    value={r.rewardText || ""}
                    onChange={(e) =>
                      updateRound(i, { rewardText: e.target.value })
                    }
                  />
                </div>
                <div className="tweak-row">
                  <label>提示圖片網址（選填）</label>
                  <input
                    value={r.image || ""}
                    onChange={(e) => updateRound(i, { image: e.target.value })}
                  />
                </div>
              </div>
            ))}
          </>
        )}
      </div>
    </div>
  );
}

// ------- App Shell -------
function App() {
  const [tweaks, setTweaks] = useState(window.__TWEAKS__);
  const [screen, setScreen] = useState("start"); // start | challenge | end
  const [round, setRound] = useState(0);
  const [solved, setSolved] = useState(() => tweaks.rounds.map(() => false));
  const [tweaksOpen, setTweaksOpen] = useState(false);

  // Persist position
  useEffect(() => {
    try {
      const s = JSON.parse(localStorage.getItem("loc-hunter") || "null");
      if (s && s.screen) {
        setScreen(s.screen);
        setRound(s.round || 0);
        setSolved(s.solved || tweaks.rounds.map(() => false));
      }
    } catch (e) {}
  }, []);
  useEffect(() => {
    try {
      localStorage.setItem(
        "loc-hunter",
        JSON.stringify({ screen, round, solved }),
      );
    } catch (e) {}
  }, [screen, round, solved]);

  // Tweaks mode messaging
  useEffect(() => {
    const onMsg = (e) => {
      const d = e.data;
      if (!d || !d.type) return;
      if (d.type === "__activate_edit_mode") setTweaksOpen(true);
      if (d.type === "__deactivate_edit_mode") setTweaksOpen(false);
    };
    window.addEventListener("message", onMsg);
    // only now announce availability
    window.parent &&
      window.parent.postMessage({ type: "__edit_mode_available" }, "*");
    return () => window.removeEventListener("message", onMsg);
  }, []);

  const start = () => {
    setRound(0);
    setSolved(tweaks.rounds.map(() => false));
    setScreen("challenge");
  };

  const handleResult = (correct) => {
    if (correct) {
      const s = solved.slice();
      s[round] = true;
      setSolved(s);
    }
    const next = round + 1;
    if (next >= tweaks.rounds.length) {
      setScreen("end");
    } else {
      setRound(next);
    }
  };

  return (
    <div
      style={{ position: "absolute", inset: 0 }}
      data-screen-label={`00 ${screen}`}
    >
      {screen === "start" && <StartScreen tweaks={tweaks} onStart={start} />}
      {screen === "challenge" && (
        <ChallengeScreen
          key={round}
          idx={round}
          total={tweaks.rounds.length}
          round={tweaks.rounds[round]}
          tweaks={tweaks}
          onResult={handleResult}
        />
      )}
      {screen === "end" && (
        <EndScreen tweaks={tweaks} solved={solved} onReplay={start} />
      )}
      <div className="scanlines" />

      {tweaksOpen && (
        <TweaksPanel
          tweaks={tweaks}
          setTweaks={setTweaks}
          onClose={() => setTweaksOpen(false)}
        />
      )}
    </div>
  );
}

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