/* Footer + Nav + Tweaks panel */

function decodeJwtPayload(token) {
  try {
    const parts = (token || "").split(".");
    if (parts.length < 2) return null;
    const base64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
    const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, "=");
    return JSON.parse(window.atob(padded));
  } catch { return null; }
}

// Optimistic session guess from whatever we can read synchronously.
// Auth now lives in http-only cookies + CSRF, so the presence of the
// CSRF stash is our first hint that the user is signed in; we'll
// confirm (and fetch the real nickname/tier) via /api/auth/session.
function guessLandingSession() {
  try {
    const legacyToken = window.localStorage.getItem("web3map_token");
    if (legacyToken) {
      const claims = decodeJwtPayload(legacyToken);
      const now = Math.floor(Date.now() / 1000);
      if (claims && (!claims.exp || claims.exp >= now) && claims.principal_type !== "guest") {
        return {
          nickname: claims.nickname || "Signed in",
          tier: claims.tier || null,
          provisional: true,
        };
      }
    }
    const csrf = window.localStorage.getItem("web3map_csrf");
    if (csrf) return { nickname: "Signed in", tier: null, provisional: true };
    return null;
  } catch { return null; }
}

function resolveLandingApiBase() {
  const host = (window.location.hostname || "").toLowerCase();
  if (host === "localhost" || host === "127.0.0.1" || host === "0.0.0.0") {
    return "http://localhost:8000";
  }
  return "https://api.web3map.ink";
}

// The API requires a Bearer access token (rotating) and the browser
// only holds the refresh cookie + a CSRF stash. Mirror the SPA's
// refresh-first handshake: POST /api/auth/refresh with the CSRF
// header, which returns a fresh access token and the current
// nickname/tier. We never touch the SPA's in-memory token — the
// refresh endpoint is idempotent and rotates the CSRF/cookie pair.
async function fetchLandingSession() {
  try {
    const base = resolveLandingApiBase();
    const csrf = window.localStorage.getItem("web3map_csrf");
    if (!csrf) return null;
    const res = await fetch(base + "/api/auth/refresh", {
      method: "POST",
      credentials: "include",
      headers: {
        "Content-Type": "application/json",
        "X-Web3Map-CSRF": csrf,
      },
    });
    if (!res.ok) return null;
    const tokens = await res.json();
    if (!tokens || !tokens.access_token) return null;
    if (tokens.csrf_token) {
      try { window.localStorage.setItem("web3map_csrf", tokens.csrf_token); } catch {}
    }
    const claims = decodeJwtPayload(tokens.access_token);
    if (!claims) return null;
    if (claims.principal_type === "guest") return null;
    const now = Math.floor(Date.now() / 1000);
    if (claims.exp && claims.exp < now) return null;
    const nickname = tokens.nickname || claims.nickname || "Signed in";
    return {
      nickname,
      tier: claims.tier || null,
      provisional: false,
    };
  } catch { return null; }
}

const Nav = ({ onOpenTweaks }) => {
  const [session, setSession] = React.useState(() => guessLandingSession());
  React.useEffect(() => {
    let mounted = true;
    const refresh = () => {
      fetchLandingSession().then((s) => { if (mounted) setSession(s); });
    };
    refresh();
    const onFocus = () => refresh();
    window.addEventListener("focus", onFocus);
    window.addEventListener("storage", refresh);
    const t = window.setInterval(refresh, 60000);
    return () => {
      mounted = false;
      window.removeEventListener("focus", onFocus);
      window.removeEventListener("storage", refresh);
      window.clearInterval(t);
    };
  }, []);
  const signedIn = !!session;
  const nickLabel = signedIn
    ? (session.nickname && session.nickname.trim()) || "Signed in"
    : null;
  const tierLabel = signedIn && session.tier && session.tier !== "free"
    ? session.tier.toUpperCase()
    : null;
  return (
    <nav className="nav">
      <div className="container nav-inner">
        <a href="#" className="logo">
          <img src="/landing/assets/logo.svg" alt="" aria-hidden="true" className="logo-mark logo-mark-img"/>
          Web3 Map
        </a>
        <div className="nav-links">
          <a href="#product">Product</a>
          <a href="#capabilities">How it works</a>
          <a href="#cases">Track record</a>
          <a href="#pricing">Pricing</a>
        </div>
        <div className="nav-right">
          {signedIn ? (
            <React.Fragment>
              <a href="/mypage" className="nav-user" title="Go to account">
                <span className="nav-user-dot"/>
                <span className="nav-user-nick">{nickLabel}</span>
                {tierLabel && <span className="nav-user-tier">{tierLabel}</span>}
              </a>
              <a href="/arbitrage" className="btn btn-primary" style={{height: 34, padding: "0 14px"}}>
                Open dashboard
              </a>
            </React.Fragment>
          ) : (
            <React.Fragment>
              <a href="/login" className="btn btn-ghost" style={{height: 34, padding: "0 14px"}}>Sign in</a>
              <a href="/arbitrage" className="btn btn-primary" style={{height: 34, padding: "0 14px"}}>Start app</a>
            </React.Fragment>
          )}
        </div>
      </div>
    </nav>
  );
};

const NOTICES = [
  {
    tag: "Signals, not advice",
    body: "web3map surfaces price events. Every trade decision — and every loss from that decision — is yours. Nothing on this site is investment advice.",
  },
  {
    tag: "Priced at a $1,000 fill",
    body: "Spreads, fees, ETA and net profit are simulations at a $1,000 notional. Real fills diverge with market depth, latency, gas and funding that move between your read and your send.",
  },
  {
    tag: "Cross-chain risk stays with the route",
    body: "Bridge credit, chain finality, exchange outages and smart-contract risk belong to the venues and bridges we quote. web3map doesn't underwrite any of them.",
  },
  {
    tag: "Pro is slot-based, non-refundable",
    body: "Subscribing reserves your personal slot the moment the x402 payment clears, so partial or full refunds aren't available. To stop, simply don't pay the next cycle — there's no auto-renew lock-in.",
  },
];

const Notice = () => (
  <section className="notice-section">
    <div className="container">
      <div className="notice-head">
        <div className="eyebrow"><span className="dot"/>Before you start</div>
        <h2 className="notice-title">A few things worth knowing.</h2>
      </div>
      <ol className="notice-grid">
        {NOTICES.map((n, i) => (
          <li key={i} className="notice-item">
            <span className="notice-num mono">{String(i + 1).padStart(2, "0")}</span>
            <div className="notice-body">
              <div className="notice-tag">{n.tag}</div>
              <p className="notice-text">{n.body}</p>
            </div>
          </li>
        ))}
      </ol>
    </div>
  </section>
);

const Footer = () => (
  <footer>
    <div className="container">
      <div className="footer-grid">
        <div className="footer-col">
          <a href="#" className="logo" style={{display: "inline-flex", alignItems: "center", gap: 10, marginBottom: 14}}>
            <img src="/landing/assets/logo.svg" alt="" aria-hidden="true" className="logo-mark logo-mark-img"/>
            Web3 Map
          </a>
          <p style={{fontSize: 13.5, color: "var(--fg-3)", maxWidth: 36 + "ch", lineHeight: 1.55}}>
            Find arbitrages and exploits in under a minute.
          </p>
          <div className="whisper static">$w3m?</div>
        </div>
        <div className="footer-col">
          <h5>Product</h5>
          <a href="/arbitrage">Arbitrage</a>
          <a href="/arbitrage#new">New entries</a>
          <a href="/arbitrage#spikes">Price spikes</a>
        </div>
        <div className="footer-col">
          <h5>Follow</h5>
          <a href="https://x.com/Web3MapInk" target="_blank" rel="noopener noreferrer">X</a>
          <a href="https://x.com/LHW0803" target="_blank" rel="noopener noreferrer">nananaa.eth</a>
        </div>
      </div>
      <div className="footer-bottom">
        <span>© 2026 Web3 Map — Realtime web3 price index and arbitrage opportunities dashboard.</span>
        <span>Paid via x402 · USDC on Base</span>
      </div>
    </div>
  </footer>
);

const Tweaks = ({ defs, setDef, open }) => {
  const [copyMsg, setCopyMsg] = React.useState("");
  const copyJson = () => {
    const payload = JSON.stringify(defs, null, 2);
    const done = () => { setCopyMsg("copied!"); setTimeout(() => setCopyMsg(""), 1400); };
    try {
      if (navigator.clipboard && navigator.clipboard.writeText) {
        navigator.clipboard.writeText(payload).then(done, () => { setCopyMsg("copy failed"); });
        return;
      }
    } catch {}
    const ta = document.createElement("textarea");
    ta.value = payload;
    document.body.appendChild(ta);
    ta.select();
    try { document.execCommand("copy"); done(); } catch { setCopyMsg("copy failed"); }
    document.body.removeChild(ta);
  };
  const resetSaved = () => {
    try { localStorage.removeItem("w3m_defs_v7"); } catch {}
    window.location.reload();
  };
  return (
    <div className={"tweaks-panel " + (open ? "open" : "")}>
      <div className="tweaks-head">
        <span>Tweaks</span>
        <span style={{color: "var(--fg-4)"}}>web3map</span>
      </div>
      <div className="tweaks-body">
        <div className="tweak-row">
          <label>Accent</label>
          <div className="opts">
            {["green", "amber", "blue", "mono"].map(v => (
              <button key={v} className={defs.accent === v ? "on" : ""} onClick={() => setDef("accent", v)}>{v}</button>
            ))}
          </div>
        </div>
        <div className="tweak-row">
          <label>Hero grid background</label>
          <div className="opts">
            {["on", "off"].map(v => (
              <button key={v} className={defs.grid === v ? "on" : ""} onClick={() => setDef("grid", v)}>{v}</button>
            ))}
          </div>
        </div>
        <div className="tweak-row">
          <label>Graph X position <span style={{color: "var(--fg-4)", fontVariantNumeric: "tabular-nums"}}>{defs.graphX}%</span></label>
          <input type="range" min="-60" max="30" step="1" value={defs.graphX} onChange={e => setDef("graphX", Number(e.target.value))}/>
        </div>
        <div className="tweak-row">
          <label>Graph Y position <span style={{color: "var(--fg-4)", fontVariantNumeric: "tabular-nums"}}>{defs.graphY}%</span></label>
          <input type="range" min="-120" max="30" step="1" value={defs.graphY} onChange={e => setDef("graphY", Number(e.target.value))}/>
        </div>
        <div className="tweak-row">
          <label>Graph size <span style={{color: "var(--fg-4)", fontVariantNumeric: "tabular-nums"}}>{defs.graphSize}%</span></label>
          <input type="range" min="30" max="160" step="1" value={defs.graphSize} onChange={e => setDef("graphSize", Number(e.target.value))}/>
        </div>
        <div className="tweak-row">
          <label>Glow intensity <span style={{color: "var(--fg-4)", fontVariantNumeric: "tabular-nums"}}>{defs.glowIntensity}%</span></label>
          <input type="range" min="0" max="200" step="5" value={defs.glowIntensity} onChange={e => setDef("glowIntensity", Number(e.target.value))}/>
        </div>
        <div className="tweak-row">
          <label>Graph rotate <span style={{color: "var(--fg-4)", fontVariantNumeric: "tabular-nums"}}>{defs.graphRotate || 0}°</span></label>
          <input type="range" min="-180" max="180" step="1" value={defs.graphRotate || 0} onChange={e => setDef("graphRotate", Number(e.target.value))}/>
        </div>
        <div className="tweak-row">
          <label>Graph opacity <span style={{color: "var(--fg-4)", fontVariantNumeric: "tabular-nums"}}>{defs.graphOpacity ?? 100}%</span></label>
          <input type="range" min="0" max="100" step="1" value={defs.graphOpacity ?? 100} onChange={e => setDef("graphOpacity", Number(e.target.value))}/>
        </div>
        <div className="tweak-row" style={{flexDirection: "column", alignItems: "stretch", gap: 8}}>
          <div style={{display: "flex", gap: 8}}>
            <button onClick={copyJson} style={{flex: 1}}>Copy JSON</button>
            <button onClick={resetSaved} style={{flex: 1}}>Reset saved</button>
          </div>
          {copyMsg && <div style={{fontSize: 10, color: "var(--accent-ink)"}}>{copyMsg}</div>}
          <pre style={{
            margin: 0, padding: 8, fontSize: 10, lineHeight: 1.45,
            background: "var(--bg-sunken)", border: "1px solid var(--hairline)",
            borderRadius: 4, overflow: "auto", maxHeight: 160,
            fontFamily: "var(--font-mono)", color: "var(--fg-2)",
          }}>{JSON.stringify(defs, null, 2)}</pre>
        </div>
      </div>
    </div>
  );
};

Object.assign(window, { Nav, Notice, Footer, Tweaks });
