// CrashyStars landing — interactivity layer.
// Most of the page is static HTML; this layer wires up:
//   - quick-buy tabs (Stars / Gift / TON)
//   - pack selection + summary recomputation
//   - payment method selection
//   - showcase → buy tab deep-link
//   - tweaks panel (color, density, SEO length, hero alignment)

const { useState, useEffect } = React;

/* ── Quick-buy widget ──────────────────────────────────────────── */
function initBuyWidget() {
  const card = document.querySelector('.buy-card');
  if (!card) return;

  const tabs = card.querySelectorAll('.buy-tab');
  const panels = card.querySelectorAll('.panel');
  const side = card.querySelector('.buy-side');
  if (!side) return;

  const rcp = {
    target: side.querySelector('[data-rcp-target]'),
    em: side.querySelector('[data-rcp-em]'),
    title: side.querySelector('[data-rcp-title]'),
    meta: side.querySelector('[data-rcp-meta]'),
    tariff: side.querySelector('[data-rcp-tariff]'),
    user: side.querySelector('[data-rcp-user]'),
    pay: side.querySelector('[data-rcp-pay]'),
    save: side.querySelector('[data-rcp-save]'),
    price: side.querySelector('[data-rcp-price]'),
    price2: side.querySelector('[data-rcp-price2]'),
    avatar: side.querySelector('[data-rcp-avatar]'),
  };

  function fmtRub(v) { return (+v).toLocaleString('ru-RU') + '₽'; }
  function fmtUsd(v) { return '$' + (+v).toFixed(2); }
  function fmtMoney(rub, usd) {
    return document.body.dataset.currency === 'usd' ? fmtUsd(usd) : fmtRub(rub);
  }

  // Telegram username: letters/digits/underscore, 4–32 chars (mirrors server).
  const TG_USERNAME_RE = /^[a-zA-Z0-9_]{4,32}$/;
  const _avatarCache = new Map(); // username(lower) -> url|null
  const _avatarTimers = new WeakMap(); // panel -> timeoutId
  const _avatarSeq = new WeakMap();  // panel -> last seq id

  function setAvatar(url) {
    if (!rcp.avatar) return;
    if (url) {
      rcp.avatar.src = url;
      rcp.avatar.hidden = false;
    } else {
      rcp.avatar.removeAttribute('src');
      rcp.avatar.hidden = true;
    }
  }

  function fetchAvatar(panel, uname) {
    const key = uname.toLowerCase();
    if (_avatarCache.has(key)) {
      setAvatar(_avatarCache.get(key));
      return;
    }
    const seq = (_avatarSeq.get(panel) || 0) + 1;
    _avatarSeq.set(panel, seq);
    fetch('/api/avatar?username=' + encodeURIComponent(uname), { credentials: 'same-origin' })
      .then(r => r.ok ? r.json() : null)
      .then(j => {
        if (_avatarSeq.get(panel) !== seq) return; // a newer query superseded us
        const url = (j && j.ok && j.url) ? j.url : null;
        _avatarCache.set(key, url);
        // Only paint if the input still matches
        const input = panel.querySelector('[data-username-input]');
        const cur = (input && input.value || '').replace(/^@+/, '').trim();
        if (cur.toLowerCase() === key) setAvatar(url);
      })
      .catch(() => { /* ignore */ });
  }

  function setUser(panel) {
    const input = panel.querySelector('[data-username-input]') || panel.querySelector('input[type="text"]');
    const raw = (input && input.value || '').replace(/^@+/, '').trim();
    const display = raw || 'username';
    if (rcp.target) rcp.target.textContent = '@' + display;
    if (rcp.user) rcp.user.textContent = '@' + display;

    const box = input && input.closest('.field-box');
    const valid = TG_USERNAME_RE.test(raw);
    if (box) {
      box.classList.toggle('is-valid', valid);
      box.classList.toggle('is-invalid', !!raw && !valid);
    }

    // Debounce the avatar fetch — only fire when the username is shape-valid.
    clearTimeout(_avatarTimers.get(panel));
    if (!valid) {
      setAvatar(null);
      return;
    }
    _avatarTimers.set(panel, setTimeout(() => fetchAvatar(panel, raw), 400));
  }

  function update(panel) {
    if (!panel) return;
    const sel = panel.querySelector('.pack.sel');
    const pay = panel.querySelector('.pay-opt.sel');

    if (sel) {
      if (rcp.em) rcp.em.textContent = sel.dataset.em || '⭐';
      if (rcp.title) rcp.title.textContent = (sel.dataset.label || '') + ' · от CrashyStars';
      if (rcp.meta) rcp.meta.textContent = sel.dataset.meta || 'Доставка за ~30 секунд';
      if (rcp.tariff) rcp.tariff.textContent = sel.dataset.label || '';
      if (rcp.save) rcp.save.textContent = sel.dataset.save || '0%';
      const rubVal = +(sel.dataset.priceRub || 0);
      const usdVal = +(sel.dataset.priceUsd || (rubVal / 73.2));
      const price = fmtMoney(rubVal, usdVal);
      if (price) {
        if (rcp.price) {
          rcp.price.classList.remove('popping');
          void rcp.price.offsetWidth;
          rcp.price.classList.add('popping');
          rcp.price.textContent = price;
        }
        if (rcp.price2) rcp.price2.textContent = price;
      }
    }

    if (pay && rcp.pay) {
      const lbl = pay.dataset.payLabel || (pay.querySelector('b') && pay.querySelector('b').textContent) || '';
      const sub = lbl === 'СБП' ? ' · 0%' : '';
      rcp.pay.textContent = lbl + sub;
    }

    setUser(panel);
  }

  function activate(tabName) {
    tabs.forEach(t => t.classList.toggle('active', t.dataset.tab === tabName));
    panels.forEach(p => p.classList.toggle('active', p.dataset.panel === tabName));
    side.dataset.mode = tabName;
    const panel = card.querySelector(`.panel[data-panel="${tabName}"]`);
    update(panel);
  }
  tabs.forEach(t => t.addEventListener('click', () => activate(t.dataset.tab)));

  document.querySelectorAll('[data-tab]').forEach(el => {
    if (el.classList.contains('buy-tab')) return;
    el.addEventListener('click', () => activate(el.dataset.tab));
  });

  panels.forEach(panel => {
    panel.querySelectorAll('.pack').forEach(pk => {
      pk.addEventListener('click', () => {
        panel.querySelectorAll('.pack').forEach(p => p.classList.remove('sel'));
        pk.classList.add('sel');
        // Sync custom-qty input back to pack value if present
        const qIn = panel.querySelector('input[type="number"]');
        if (qIn && pk.dataset.qty && !isNaN(+pk.dataset.qty)) qIn.value = +pk.dataset.qty;
        update(panel);
      });
    });
    panel.querySelectorAll('.select-opt').forEach(opt => {
      opt.addEventListener('click', e => {
        const box = opt.closest('.select-box');
        const label = box && box.querySelector('.select-label');
        const b = opt.querySelector('b');
        if (label && b) {
          label.textContent = b.textContent;
          box.classList.add('has-value');
        }
        if (box) box.classList.remove('open');
        // Update receipt pay
        if (rcp.pay) {
          const lbl = opt.dataset.payLabel || (b && b.textContent) || '';
          rcp.pay.textContent = lbl;
        }
        e.stopPropagation();
      });
    });
    const userInput = panel.querySelector('[data-username-input]') || panel.querySelector('input[type="text"]');
    if (userInput) userInput.addEventListener('input', () => setUser(panel));

    // Custom quantity → recompute from per-unit rate of currently selected pack
    const qtyInput = panel.querySelector('input[type="number"]');
    if (qtyInput) {
      qtyInput.addEventListener('input', () => {
        const packs = panel.querySelectorAll('.pack');
        const sel = panel.querySelector('.pack.sel') || packs[0];
        if (!sel) return;
        const baseQty = +sel.dataset.qty || 1;
        const baseRub = +sel.dataset.priceRub || 0;
        let v = parseFloat(qtyInput.value);
        if (!isFinite(v) || v < 1) return;
        const max = +qtyInput.max || Infinity;
        const min = +qtyInput.min || 1;
        v = Math.min(Math.max(v, min), max);
        const rub = (baseRub / baseQty) * v;
        const baseUsd = +sel.dataset.priceUsd || 0;
        const usd = (baseUsd / baseQty) * v;
        const unit = sel.dataset.em || '⭐';
        // Update receipt directly (skip the pack-derived update path)
        if (rcp.em) rcp.em.textContent = unit;
        if (rcp.title) rcp.title.textContent = `${v.toLocaleString('ru-RU')} ${unit} · от CrashyStars`;
        if (rcp.tariff) rcp.tariff.textContent = `${v.toLocaleString('ru-RU')} ${unit}`;
        if (rcp.meta) rcp.meta.textContent = sel.dataset.meta || 'Доставка за ~30 секунд';
        const priceStr = fmtMoney(Math.round(rub), Math.round(usd * 100) / 100);
        if (rcp.price) {
          rcp.price.classList.remove('popping');
          void rcp.price.offsetWidth;
          rcp.price.classList.add('popping');
          rcp.price.textContent = priceStr;
        }
        if (rcp.price2) rcp.price2.textContent = priceStr;
        // De-select packs that don't match (so the UI stays consistent)
        const matching = [...packs].find(p => +p.dataset.qty === v);
        packs.forEach(p => p.classList.remove('sel'));
        if (matching) matching.classList.add('sel');
        setUser(panel);
      });
    }
  });

  update(card.querySelector('.panel.active'));

  // Expose for currency toggle in the header
  window.__refreshReceipt = () => update(card.querySelector('.panel.active'));

  // ── Dropdown open/close (delegated, works for all .select-box on the page) ──
  const dropdowns = card.querySelectorAll('.select-box');
  dropdowns.forEach(box => {
    box.addEventListener('click', e => {
      // Clicks on .select-opt are handled separately (they close + select).
      if (e.target.closest('.select-opt')) return;
      // Clicks anywhere else inside the menu shouldn't toggle.
      if (e.target.closest('.select-menu')) return;
      const wasOpen = box.classList.contains('open');
      dropdowns.forEach(d => d !== box && d.classList.remove('open'));
      box.classList.toggle('open', !wasOpen);
    });
  });
  document.addEventListener('click', e => {
    if (!e.target.closest('.select-box')) {
      dropdowns.forEach(d => d.classList.remove('open'));
    }
  });
}

/* ── Live feed: subtle re-ordering every few seconds ──────────── */
function initLiveFeed() {
  const list = document.getElementById('live-list');
  if (!list) return;
  const TIME_LABELS = ['только что', '8 сек', '14 сек', '23 сек', '38 сек', '52 сек', '1 мин', '2 мин', '3 мин'];
  setInterval(() => {
    const rows = [...list.children];
    if (rows.length < 2) return;
    // pop last → prepend (rotate ticker)
    list.insertBefore(rows[rows.length - 1], rows[0]);
    [...list.children].forEach((r, i) => {
      const t = r.querySelector('.lr-time');
      if (t) t.textContent = TIME_LABELS[i] || `${i + 1} мин`;
    });
  }, 4200);
}

/* ── Header toggle groups (lang / currency) ───────────────────── */
function initHeaderToggles() {
  document.querySelectorAll('[data-toggle-group]').forEach(group => {
    const groupName = group.dataset.toggleGroup; // "lang" | "currency"
    group.addEventListener('click', e => {
      const opt = e.target.closest('.opt');
      if (!opt || !group.contains(opt)) return;
      group.querySelectorAll('.opt').forEach(o => o.classList.remove('active'));
      opt.classList.add('active');
      // Persist on body so CSS .ccy-rub / .ccy-usd rules + JS formatters react
      if (groupName === 'currency') {
        const v = opt.dataset.currency || 'rub';
        document.body.dataset.currency = v;
        // Refresh the receipt to use the new currency
        if (typeof window.__refreshReceipt === 'function') window.__refreshReceipt();
      } else if (groupName === 'lang') {
        document.body.dataset.lang = opt.dataset.lang || 'ru';
      }
    });
  });
}

/* ── Smooth-scroll for in-page anchor links ───────────────────── */
function initSmoothScroll() {
  document.querySelectorAll('a[href^="#"]').forEach(a => {
    a.addEventListener('click', e => {
      const href = a.getAttribute('href');
      if (!href || href === '#') return;
      const tgt = document.querySelector(href);
      if (!tgt) return;
      e.preventDefault();
      tgt.scrollIntoView({ behavior: 'smooth', block: 'start' });
    });
  });
}

/* ── Hero deck mouse tilt ─────────────────────────────────────── */
function initHeroDeckTilt() {
  const deck = document.querySelector('.hero-deck');
  if (!deck) return;
  // Respect reduced-motion preference — keep static drift, no tilt
  if (matchMedia('(prefers-reduced-motion: reduce)').matches) return;
  // Touch / coarse pointer — skip tilt; tap should just navigate
  if (matchMedia('(pointer: coarse)').matches) return;

  let raf = 0;
  let targetMx = 0, targetMy = 0;
  let curMx = 0, curMy = 0;
  const host = deck.parentElement; // .hero-art

  function loop() {
    // ease toward target for smoothness
    curMx += (targetMx - curMx) * 0.12;
    curMy += (targetMy - curMy) * 0.12;
    deck.style.setProperty('--mx', curMx.toFixed(3));
    deck.style.setProperty('--my', curMy.toFixed(3));
    if (Math.abs(targetMx - curMx) > 0.001 || Math.abs(targetMy - curMy) > 0.001) {
      raf = requestAnimationFrame(loop);
    } else {
      raf = 0;
      // If we've coasted back to 0,0, drop tilt mode to resume drift animation
      if (targetMx === 0 && targetMy === 0) deck.removeAttribute('data-tilt');
    }
  }
  function start() { if (!raf) raf = requestAnimationFrame(loop); }

  host.addEventListener('mousemove', e => {
    const rect = host.getBoundingClientRect();
    targetMx = ((e.clientX - rect.left) / rect.width - 0.5) * 2;
    targetMy = ((e.clientY - rect.top) / rect.height - 0.5) * 2;
    deck.setAttribute('data-tilt', 'on');
    start();
  });
  host.addEventListener('mouseleave', () => {
    targetMx = 0; targetMy = 0;
    start();
  });
}

/* ── Tweaks panel ─────────────────────────────────────────────── */
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "brand",
  "density": "regular",
  "seoLength": "full",
  "showLiveFeed": true,
  "showCompare": true,
  "showReferral": true,
  "starsBadge": "★ Хит"
}/*EDITMODE-END*/;

const ACCENT_PRESETS = {
  brand:  { teal: '#5ee5d9', blue: '#6d98ef', violet: '#b39aff' },
  sunset: { teal: '#ffd86b', blue: '#ff9bd2', violet: '#b39aff' },
  neon:   { teal: '#39ff88', blue: '#39d4ff', violet: '#b78aff' },
  tg:     { teal: '#7ec0ff', blue: '#5b8cff', violet: '#9badff' },
};

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  useEffect(() => {
    // accent
    const p = ACCENT_PRESETS[t.accent] || ACCENT_PRESETS.brand;
    const root = document.documentElement;
    root.style.setProperty('--c-teal', p.teal);
    root.style.setProperty('--c-blue', p.blue);
    root.style.setProperty('--c-violet', p.violet);
    root.style.setProperty('--grad-brand', `linear-gradient(110deg, ${p.teal} 0%, ${p.blue} 50%, ${p.violet} 100%)`);
    root.style.setProperty('--grad-brand-soft', `linear-gradient(110deg, ${hexA(p.teal, .18)} 0%, ${hexA(p.blue, .18)} 50%, ${hexA(p.violet, .18)} 100%)`);

    // density + seo length
    document.body.dataset.density = t.density;
    document.body.dataset.seo = t.seoLength;

    // section visibility
    const live = document.querySelector('.live');
    if (live) live.style.display = t.showLiveFeed ? '' : 'none';
    const cmp = document.querySelector('.compare');
    if (cmp) cmp.style.display = t.showCompare ? '' : 'none';
    const ref = document.querySelector('.refer');
    if (ref) ref.style.display = t.showReferral ? '' : 'none';
  }, [t]);

  return (
    <TweaksPanel title="Tweaks">
      <TweakSection label="Цвет акцента" />
      <TweakRadio value={t.accent} options={['brand', 'sunset', 'neon', 'tg']}
        onChange={v => setTweak('accent', v)} />

      <TweakSection label="Плотность" />
      <TweakRadio value={t.density} options={['compact', 'regular', 'cozy']}
        onChange={v => setTweak('density', v)} />

      <TweakSection label="SEO-текст" />
      <TweakRadio value={t.seoLength} options={['short', 'full']}
        onChange={v => setTweak('seoLength', v)} />

      <TweakSection label="Секции" />
      <TweakToggle label="Лента «прямо сейчас»" value={t.showLiveFeed}
        onChange={v => setTweak('showLiveFeed', v)} />
      <TweakToggle label="Таблица сравнения" value={t.showCompare}
        onChange={v => setTweak('showCompare', v)} />
      <TweakToggle label="Реферальный блок" value={t.showReferral}
        onChange={v => setTweak('showReferral', v)} />
    </TweaksPanel>
  );
}

function hexA(hex, alpha) {
  const h = hex.replace('#', '');
  const r = parseInt(h.slice(0, 2), 16);
  const g = parseInt(h.slice(2, 4), 16);
  const b = parseInt(h.slice(4, 6), 16);
  return `rgba(${r},${g},${b},${alpha})`;
}

/* ── Mount ─────────────────────────────────────────────────────── */
// Babel-standalone transpiles async — by the time this runs, DOMContentLoaded
// has already fired, so we run init inline (or wait if doc is still loading).
function bootAll() {
  initBuyWidget();
  initLiveFeed();
  initSmoothScroll();
  initHeaderToggles();
  const root = document.createElement('div');
  root.id = '__tweaks_root';
  document.body.appendChild(root);
  ReactDOM.createRoot(root).render(<App />);
}
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', bootAll);
} else {
  bootAll();
}
