// EL3AB Global App JS

const App = {
  token: localStorage.getItem('el3ab_token'),
  user: JSON.parse(localStorage.getItem('el3ab_user') || 'null'),

  async fetch(url, options = {}) {
    try {
      const headers = {
        'Content-Type': 'application/json',
        ...(options.headers || {}),
      };
      if (this.token) {
        headers['Authorization'] = 'Bearer ' + this.token;
      }
      const res = await fetch(url, { ...options, headers });
      if (res.status === 401) {
        this.logout();
        return null;
      }
      return res.json();
    } catch (e) {
      return null;
    }
  },

  setAuth(token, user) {
    this.token = token;
    this.user = user;
    localStorage.setItem('el3ab_token', token);
    localStorage.setItem('el3ab_user', JSON.stringify(user));
  },

  logout() {
    this.token = null;
    this.user = null;
    localStorage.removeItem('el3ab_token');
    localStorage.removeItem('el3ab_user');
    window.location.href = '/login';
  },

  isLoggedIn() {
    return !!this.token;
  },

  toast(message, type = 'info') {
    const container = document.getElementById('toast-container');
    if (!container) return;
    const el = document.createElement('div');
    el.className = 'toast' + (type !== 'info' ? ' toast-' + type : '');
    const icons = { success: 'check', error: 'x', info: 'bell' };
    const icon = icons[type] || icons.info;
    el.innerHTML = '<svg class="toast-icon"><use href="/public/icons/sprite.svg#icon-' + icon + '"></use></svg>' +
      '<span>' + message + '</span><span class="toast-progress"></span>';
    container.appendChild(el);
    // Swipe to dismiss
    let startX = 0;
    el.addEventListener('touchstart', (e) => { startX = e.touches[0].clientX; });
    el.addEventListener('touchmove', (e) => {
      const diff = e.touches[0].clientX - startX;
      if (Math.abs(diff) > 20) el.style.transform = 'translateX(' + diff + 'px)';
    });
    el.addEventListener('touchend', (e) => {
      const diff = e.changedTouches[0].clientX - startX;
      if (Math.abs(diff) > 80) { el.remove(); return; }
      el.style.transform = '';
    });
    setTimeout(() => {
      el.style.opacity = '0';
      el.style.transform = 'translateY(-8px)';
      el.style.transition = 'all 0.3s';
      setTimeout(() => el.remove(), 300);
    }, 3000);
  },

  async loadProfile() {
    if (!this.token) return;
    const data = await this.fetch('/api/profile');
    if (data && data.profile) {
      const p = data.profile;
      const coins = document.getElementById('header-coins');
      const gems = document.getElementById('header-gems');
      if (coins) this.animateNumber(coins, p.coins || 0);
      if (gems) this.animateNumber(gems, p.gems || 0);
      // Win streak fire badge
      const streak = p.win_streak || 0;
      document.querySelectorAll('.nav-desktop-item[href="/profile"], .nav-bottom-item[href="/profile"]').forEach(el => {
        el.classList.toggle('streak-fire', streak >= 3);
      });
    }
  },

  async optimistic(updateFn, revertFn, promise) {
    updateFn();
    try {
      const res = await promise;
      if (!res || res.error) {
        revertFn();
        if (res && res.error) this.toast(res.error, 'error');
      }
      return res;
    } catch (e) {
      revertFn();
      return null;
    }
  },

  animateNumber(el, target, duration) {
    duration = duration || 600;
    const start = parseInt(el.textContent.replace(/[^\d]/g, '')) || 0;
    const diff = target - start;
    if (diff === 0) return;
    const startTime = performance.now();
    const step = (now) => {
      const t = Math.min((now - startTime) / duration, 1);
      const ease = 1 - Math.pow(1 - t, 3);
      el.textContent = Math.round(start + diff * ease).toLocaleString();
      if (t < 1) requestAnimationFrame(step);
    };
    requestAnimationFrame(step);
  },

  // ===== Bottom Sheet =====
  showSheet(html) {
    let backdrop = document.querySelector('.sheet-backdrop');
    let sheet = document.querySelector('.sheet');
    if (!backdrop) {
      backdrop = document.createElement('div');
      backdrop.className = 'sheet-backdrop';
      document.body.appendChild(backdrop);
      sheet = document.createElement('div');
      sheet.className = 'sheet';
      sheet.innerHTML = '<div class="sheet-handle"></div><div class="sheet-content"></div>';
      document.body.appendChild(sheet);
      backdrop.addEventListener('click', () => this.hideSheet());
    }
    sheet.querySelector('.sheet-content').innerHTML = html;
    requestAnimationFrame(() => {
      backdrop.classList.add('active');
      sheet.classList.add('active');
    });
  },

  hideSheet() {
    const backdrop = document.querySelector('.sheet-backdrop');
    const sheet = document.querySelector('.sheet');
    if (backdrop) backdrop.classList.remove('active');
    if (sheet) sheet.classList.remove('active');
  },

  // ===== Request Cache =====
  _cache: {},
  async cachedFetch(url, ttl) {
    ttl = ttl || 30000;
    const now = Date.now();
    if (this._cache[url] && (now - this._cache[url].time) < ttl) {
      return this._cache[url].data;
    }
    const data = await this.fetch(url);
    if (data) this._cache[url] = { data, time: now };
    return data;
  },

  invalidateCache(url) {
    if (url) delete this._cache[url];
    else this._cache = {};
  },

  // ===== Sound System =====
  _soundEnabled: localStorage.getItem('el3ab_sound') !== 'off',
  _audioCtx: null,

  toggleSound(on) {
    this._soundEnabled = on;
    localStorage.setItem('el3ab_sound', on ? 'on' : 'off');
  },

  playSound(type) {
    if (!this._soundEnabled) return;
    if (!this._audioCtx) this._audioCtx = new (window.AudioContext || window.webkitAudioContext)();
    const ctx = this._audioCtx;
    const osc = ctx.createOscillator();
    const gain = ctx.createGain();
    osc.connect(gain);
    gain.connect(ctx.destination);
    gain.gain.value = 0.15;

    const sounds = {
      move: [440, 0.08, 'sine'],
      capture: [520, 0.12, 'square'],
      check: [660, 0.15, 'sawtooth'],
      win: [523, 0.3, 'sine'],
      lose: [220, 0.3, 'sine'],
      click: [800, 0.05, 'sine'],
      dice: [350, 0.1, 'triangle'],
      notify: [600, 0.15, 'sine'],
      home: [659, 0.2, 'sine'],
      six: [700, 0.08, 'triangle'],
      turn: [500, 0.06, 'sine'],
      error: [200, 0.15, 'square'],
    };
    const [freq, dur, wave] = sounds[type] || sounds.click;
    osc.type = wave;
    osc.frequency.value = freq;
    gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + dur);
    osc.start(ctx.currentTime);
    osc.stop(ctx.currentTime + dur);
  },

  // ===== Celebration Overlay =====
  celebrate(title) {
    const overlay = document.createElement('div');
    overlay.className = 'celebrate-overlay';
    overlay.innerHTML = '<span class="celebrate-title">' + title + '</span>';
    const colors = ['#E7A832', '#15D7FF', '#7C4DFF', '#34D399', '#EF4444', '#F59E0B'];
    for (let i = 0; i < 30; i++) {
      const p = document.createElement('span');
      p.className = 'confetti-particle';
      p.style.left = Math.random() * 100 + '%';
      p.style.top = '-10px';
      p.style.background = colors[Math.floor(Math.random() * colors.length)];
      p.style.animationDelay = (Math.random() * 0.5) + 's';
      p.style.animationDuration = (1.5 + Math.random()) + 's';
      overlay.appendChild(p);
    }
    document.body.appendChild(overlay);
    overlay.addEventListener('click', () => overlay.remove());
    setTimeout(() => overlay.remove(), 3500);
  },

  // ===== Navigate (soft page transition) =====
  navigate(url) {
    const main = document.querySelector('.main-inner');
    if (!main) { window.location.href = url; return; }
    main.classList.add('page-exit');
    setTimeout(() => { window.location.href = url; }, 200);
  },

  // ===== Haptic Feedback =====
  vibrate(ms) {
    if (navigator.vibrate) navigator.vibrate(ms || 10);
  }
};

document.addEventListener('DOMContentLoaded', () => {
  if (App.isLoggedIn()) {
    App.loadProfile();
  }

  // Button ripple effect + haptic
  document.addEventListener('click', (e) => {
    const btn = e.target.closest('.btn');
    if (!btn) return;
    App.vibrate(5);
    const rect = btn.getBoundingClientRect();
    const size = Math.max(rect.width, rect.height);
    const ripple = document.createElement('span');
    ripple.className = 'ripple';
    ripple.style.width = ripple.style.height = size + 'px';
    ripple.style.left = (e.clientX - rect.left - size / 2) + 'px';
    ripple.style.top = (e.clientY - rect.top - size / 2) + 'px';
    btn.appendChild(ripple);
    setTimeout(() => ripple.remove(), 500);
  });

  // Pull-to-refresh (mobile)
  let ptr_startY = 0, ptr_pulling = false;
  const mainEl = document.querySelector('.main');
  if (mainEl && 'ontouchstart' in window) {
    const indicator = document.createElement('div');
    indicator.className = 'ptr-indicator';
    indicator.innerHTML = '<svg class="icon-sm" style="color:var(--cyan)"><use href="/public/icons/sprite.svg#icon-arrow-down"></use></svg>';
    document.body.appendChild(indicator);

    mainEl.addEventListener('touchstart', (e) => {
      if (mainEl.scrollTop === 0) {
        ptr_startY = e.touches[0].clientY;
        ptr_pulling = true;
      }
    }, { passive: true });

    mainEl.addEventListener('touchmove', (e) => {
      if (!ptr_pulling) return;
      const diff = e.touches[0].clientY - ptr_startY;
      if (diff > 30) indicator.classList.add('active');
      else indicator.classList.remove('active');
    }, { passive: true });

    mainEl.addEventListener('touchend', () => {
      if (indicator.classList.contains('active')) {
        indicator.classList.remove('active');
        indicator.classList.add('loading');
        setTimeout(() => {
          indicator.classList.remove('loading');
          window.location.reload();
        }, 600);
      }
      ptr_pulling = false;
    });
  }

  // Lazy image loader
  document.querySelectorAll('.img-lazy img').forEach(img => {
    if (img.complete) img.closest('.img-lazy').classList.add('img-lazy--loaded');
    else img.addEventListener('load', () => img.closest('.img-lazy').classList.add('img-lazy--loaded'));
  });
});
