/* global React, ReactDOM, DEALS, XB, XBStore, useStoredState, TweaksPanel, useTweaks, TweakSection, TweakRadio, TweakSlider, TweakColor */
const { useEffect, useState } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#22c55e",
  "highlightIntensity": 1,
  "motion": 1,
  "density": 1
}/*EDITMODE-END*/;

// Centralized in store.jsx — see XBStore.safeUrl for the actual rules.
const safeUrl = (window.XBStore && window.XBStore.safeUrl) || ((v) => v);

function deriveAccentVars(hex) {
  const h = hex.replace("#", "");
  const r = parseInt(h.substring(0, 2), 16);
  const g = parseInt(h.substring(2, 4), 16);
  const b = parseInt(h.substring(4, 6), 16);
  const lighten = (c) => Math.min(255, Math.round(c + (255 - c) * 0.25));
  const darken = (c) => Math.round(c * 0.78);
  return {
    bright: `rgb(${lighten(r)}, ${lighten(g)}, ${lighten(b)})`,
    deep: `rgb(${darken(r)}, ${darken(g)}, ${darken(b)})`,
    glow: `rgba(${r}, ${g}, ${b}, 0.45)`,
    glowSoft: `rgba(${r}, ${g}, ${b}, 0.12)`,
    glowMid: `rgba(${r}, ${g}, ${b}, 0.30)`
  };
}

function AgeGate({ onPass }) {
  const [denied, setDenied] = React.useState(false);
  const [exiting, setExiting] = React.useState(false);
  // Run the CSS exit animation before notifying the parent so the gate
  // doesn't pop out abruptly. 320ms matches the ageFadeOut/ageCardOut
  // duration in styles.css — keep them in sync if either changes.
  const handleYes = () => {
    if (exiting) return;
    setExiting(true);
    setTimeout(onPass, 320);
  };
  if (denied) {
    return (
      <div className={"age-gate" + (exiting ? " exiting" : "")}>
        <div className="age-gate-card">
          <div className="age-gate-eyebrow">● ACCESS DENIED</div>
          <h2>You must be <em>18 or older</em><br />to view this site.</h2>
          <p>Gambling content is restricted to adults. If you reached this page in error, please leave now.</p>
          <a className="age-gate-leave" href="https://www.google.com">Leave site →</a>
        </div>
      </div>
    );
  }
  return (
    <div className={"age-gate" + (exiting ? " exiting" : "")}>
      <div className="age-gate-card">
        <div className="age-gate-badge">18+</div>
        <div className="age-gate-eyebrow">● AGE VERIFICATION</div>
        <h2>Are you <em>18 or older?</em></h2>
        <p>This site contains casino bonus offers intended for adults only. Please confirm your age to continue.</p>
        <div className="age-gate-actions">
          <button className="age-btn no" onClick={() => setDenied(true)}>No</button>
          <button className="age-btn yes" onClick={handleYes}>Yes, I'm 18+</button>
        </div>
        <span className="age-gate-foot">Gamble responsibly. By continuing, you accept our terms.</span>
      </div>
    </div>
  );
}

// Read-only view of a store key — same wiring as `useStoredState` exposed
// by store.jsx, but we discard the setter since the public site never writes.
function useStore(key, loader) {
  const [val] = useStoredState(key, loader);
  return val;
}

function App() {
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [toast, showToast] = XB.useToast();
  const [verified, setVerified] = React.useState(() => {
    // Skip the gate when rendered inside an iframe — used for the admin's
    // live preview, where the age modal would obscure what the user is
    // editing. Real visitors always hit the top-level document.
    try {
      if (window.self !== window.top) return true;
      return localStorage.getItem("xb_age_ok") === "1";
    } catch (e) { return true; }
  });
  const passAge = () => {
    try { localStorage.setItem("xb_age_ok", "1"); } catch (e) {}
    setVerified(true);
  };

  // Record a single page visit per browser tab. Skipped when rendered in
  // an iframe (the admin's live preview) so admin previews don't inflate
  // visit counts.
  useEffect(() => {
    if (!XBStore.isSupabaseEnabled) return;
    try { if (window.self !== window.top) return; } catch (e) {}
    XBStore.recordVisit();
  }, []);

  const deals    = useStore(XBStore.KEYS.DEALS,    () => XBStore.loadDeals(DEALS));
  const brand    = useStore(XBStore.KEYS.BRAND,    () => XBStore.loadBrand());
  const profile  = useStore(XBStore.KEYS.PROFILE,  () => XBStore.loadProfile());
  const settings = useStore(XBStore.KEYS.SETTINGS, () => XBStore.loadSettings());

  // Brand-controlled values. Tweaks panel still nudges them locally.
  const accent = brand.accent || tweaks.accent;
  const motionLevel = brand.motion ? tweaks.motion : 0;
  const highlight = (brand.highlightIntensity != null ? brand.highlightIntensity : 1) * (tweaks.highlightIntensity || 1);

  useEffect(() => {
    const root = document.documentElement;
    const a = deriveAccentVars(accent);
    root.style.setProperty("--accent", accent);
    root.style.setProperty("--accent-bright", a.bright);
    root.style.setProperty("--accent-deep", a.deep);
    root.style.setProperty("--accent-glow", a.glow);
    root.style.setProperty("--line", a.glowSoft);
    root.style.setProperty("--line-strong", a.glowMid);
    root.style.setProperty("--highlight-intensity", String(highlight));
    root.style.setProperty("--motion", String(motionLevel));
    root.style.setProperty("--density", String(tweaks.density));
  }, [accent, motionLevel, highlight, tweaks.density]);

  // Reflect SEO settings into the document.
  useEffect(() => {
    if (settings.title) document.title = settings.title;
    if (settings.metaDesc) {
      let m = document.querySelector('meta[name="description"]');
      if (!m) { m = document.createElement("meta"); m.setAttribute("name", "description"); document.head.appendChild(m); }
      m.setAttribute("content", settings.metaDesc);
    }
  }, [settings.title, settings.metaDesc]);

  const top = deals.find(d => d.isTopPick) || deals[0];
  const others = deals.filter(d => d !== top);

  const onClaim = (deal) => {
    showToast(`Opening ${deal.name} → ${deal.code}`);
    const url = safeUrl(deal.url);
    if (!url || url === "#") return;
    if (window.XBStore) window.XBStore.recordClaim(deal.id, deal.code);
    // Attribution: append the visitor's session token as `btag` so when
    // the casino fires a postback for a signup/FTD they can echo it back
    // and we can match conversion → click → deal. URL-encoded; merges
    // with existing query string if the affiliate URL already has params.
    let final = url;
    try {
      const token = window.XBStore && window.XBStore.getSessionToken
        ? window.XBStore.getSessionToken() : "";
      if (token) {
        const sep = url.includes("?") ? "&" : "?";
        final = url + sep + "btag=" + encodeURIComponent(token);
      }
    } catch (e) {}
    window.open(final, "_blank", "noopener,noreferrer");
  };
  const onCopy = (code) => showToast(`Copied: ${code}`);

  // Split site name into accent / suffix to mimic "XOOTIC|BONUS" pattern.
  const siteName = brand.siteName || "XOOTICBONUS";
  const sitePrefix = siteName.length > 5 ? siteName.slice(0, siteName.length - 5) : siteName;
  const siteSuffix = siteName.length > 5 ? siteName.slice(-5) : "";

  // Age gate is gated on settings.show18 — admin can disable it.
  const showAgeGate = settings.show18 && !verified;

  return (
    <>
      {showAgeGate && <AgeGate onPass={passAge} />}
      <div className="bg-stage">
        <div className="bg-grid"></div>
        <div className="bg-glow"></div>
        <div className="bg-glow-2"></div>
        <div className="bg-aurora"></div>
        <div className="bg-rays"></div>
        <div className="bg-noise"></div>
      </div>
      {brand.motion && <XB.Particles />}

      <div className="shell">
        <header className="top-bar">
          <div className="brand">
            <div className="logo-mark">
              <img className="lm-img" src="assets/avatar.png" alt={siteName} />
              <span className="lm-corner tl"></span>
              <span className="lm-corner tr"></span>
              <span className="lm-corner bl"></span>
              <span className="lm-corner br"></span>
            </div>
            <div className="brand-text">
              <span className="logo-text"><span className="accent">{sitePrefix}</span>{siteSuffix}</span>
              <span className="brand-tag">Exclusive casino bonus codes</span>
            </div>
          </div>
        </header>

        <section className="hero">
          <div className="hero-eyebrow">
            <span className="live-pulse"></span>
            HAND-PICKED · VERIFIED WEEKLY · EXCLUSIVE CODES
          </div>
          <h1>{brand.headline} <em>{brand.headlineHighlight}</em></h1>
          <p>{brand.subhead}</p>
        </section>

        {brand.liveFeed && (
          <div className="live-feed-wrap">
            <XB.CreatorCard dealCount={deals.length} profile={profile} />
          </div>
        )}

        {top && <XB.TopPick deal={top} onClaim={onClaim} onCopy={onCopy} />}

        {others.length > 0 && (
          <>
            <div className="more-label">More verified deals</div>
            <div className="deal-list">
              {others.map((d, i) => (
                <XB.DealRow key={d.id} deal={d} idx={i} onClaim={onClaim} onCopy={onCopy} />
              ))}
            </div>
          </>
        )}

        <footer className="foot">
          <div className="socials socials-lg">
            {safeUrl(profile.telegram) && (
              <a className="social-btn" href={safeUrl(profile.telegram)} target="_blank" rel="noopener noreferrer" aria-label="Telegram" style={{ animationDelay: "0s" }}>
                <svg viewBox="0 0 24 24" fill="currentColor"><path d="M22 3L2 11l6 2 2 7 4-4 5 4 3-17z" /></svg>
              </a>
            )}
            {safeUrl(profile.twitch) && (
              <a className="social-btn" href={safeUrl(profile.twitch)} target="_blank" rel="noopener noreferrer" aria-label="Twitch" style={{ animationDelay: "0.6s" }}>
                <svg viewBox="0 0 24 24" fill="currentColor"><path d="M3 3h18v12l-5 5h-4l-3 3H7v-3H3V3zm6 5h2v6H9V8zm5 0h2v6h-2V8z" /></svg>
              </a>
            )}
          </div>
        </footer>
        <div className="disclaimer">
          {settings.show18 && <><span className="badge">18+</span><span className="dot-sep">·</span></>}
          {settings.showDisclaimer && <><span>Play responsibly</span><span className="dot-sep">·</span></>}
          <span>© 2026 {siteName}</span>
        </div>
        {settings.disclosure && (
          <p className="affiliate-disclosure">{settings.disclosure}</p>
        )}
      </div>

      <XB.Toast message={toast.msg} show={toast.show} />

      <TweaksPanel title="Tweaks">
        <TweakSection title="Look & feel">
          <TweakColor
            label="Accent color"
            value={tweaks.accent}
            onChange={v => setTweak("accent", v)}
            options={["#22c55e", "#a855f7", "#f59e0b", "#06b6d4", "#ef4444", "#ec4899"]}
          />
        </TweakSection>
        <TweakSection title="Top deal emphasis">
          <TweakSlider
            label="Highlight intensity"
            value={tweaks.highlightIntensity}
            onChange={v => setTweak("highlightIntensity", v)}
            min={0} max={2} step={0.1}
            format={v => v.toFixed(1) + "×"}
          />
        </TweakSection>
        <TweakSection title="Motion & density">
          <TweakSlider
            label="Motion level"
            value={tweaks.motion}
            onChange={v => setTweak("motion", v)}
            min={0} max={2} step={0.1}
            format={v => v === 0 ? "Off" : v.toFixed(1) + "×"}
          />
          <TweakSlider
            label="Layout density"
            value={tweaks.density}
            onChange={v => setTweak("density", v)}
            min={0.7} max={1.3} step={0.05}
            format={v => v < 0.9 ? "Compact" : v > 1.1 ? "Spacious" : "Default"}
          />
        </TweakSection>
      </TweaksPanel>
    </>
  );
}

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