// UES Frontend Application Controller - High Performance 60 FPS Edition
class App {
  constructor() {
    this.currentTab = 'dashboard';
    this.courses = [];
    this.filteredCourses = [];
    this.selectedCategory = 'all';
    this.settings = {};
    this.initialized = false;
    this.isScraping = false;
    this.isEnrolling = false;
    this.udemyConnected = false;
    this.stats = {
      successfully_enrolled: 0,
      already_enrolled: 0,
      expired: 0,
      excluded: 0,
      amount_saved: '$0.00',
      ready_count: 0
    };
    this.analytics = null;

    this.catalogPage = 1;
    this.catalogPageSize = 24;
    this.vaultCourses = [];
    this.vaultFiltered = [];
    this.vaultPage = 1;
    this.vaultPageSize = 30;

    this.initDOM();
    this.startPolling();
  }

  initDOM() {
    // Window control buttons
    document.getElementById('btn-min')?.addEventListener('click', () => window.bridge.call('minimize_window'));
    document.getElementById('btn-max')?.addEventListener('click', () => window.bridge.call('maximize_window'));
    document.getElementById('btn-close')?.addEventListener('click', () => window.bridge.call('close_window'));

    // Tab navigation buttons
    document.querySelectorAll('.nav-item').forEach(item => {
      item.addEventListener('click', () => {
        const tab = item.getAttribute('data-tab');
        if (tab) this.switchTab(tab);
      });
    });

    // Search bar
    const searchInput = document.getElementById('course-search');
    if (searchInput) {
      searchInput.addEventListener('input', (e) => {
        this.filterCourses(e.target.value);
      });
    }

    // Category pills
    document.querySelectorAll('.filter-pill').forEach(pill => {
      pill.addEventListener('click', () => {
        document.querySelectorAll('.filter-pill').forEach(p => p.classList.remove('active'));
        pill.classList.add('active');
        this.selectedCategory = pill.getAttribute('data-cat') || 'all';
        this.filterCourses(document.getElementById('course-search')?.value || '');
      });
    });

    // Course Catalog Pagination
    document.getElementById('btn-catalog-prev')?.addEventListener('click', () => {
      if (this.catalogPage > 1) {
        this.catalogPage--;
        this.renderCourseGrid();
      }
    });
    document.getElementById('btn-catalog-next')?.addEventListener('click', () => {
      const maxPage = Math.ceil(this.filteredCourses.length / this.catalogPageSize) || 1;
      if (this.catalogPage < maxPage) {
        this.catalogPage++;
        this.renderCourseGrid();
      }
    });

    // Vault Toolbar Filters
    const vaultSearch = document.getElementById('vault-search');
    if (vaultSearch) {
      vaultSearch.addEventListener('input', () => this.filterVault());
    }
    document.getElementById('vault-category-filter')?.addEventListener('change', () => this.filterVault());
    document.getElementById('vault-source-filter')?.addEventListener('change', () => this.filterVault());

    // Vault Pagination
    document.getElementById('btn-vault-prev')?.addEventListener('click', () => {
      if (this.vaultPage > 1) {
        this.vaultPage--;
        this.renderVaultTable();
      }
    });
    document.getElementById('btn-vault-next')?.addEventListener('click', () => {
      const maxPage = Math.ceil(this.vaultFiltered.length / this.vaultPageSize) || 1;
      if (this.vaultPage < maxPage) {
        this.vaultPage++;
        this.renderVaultTable();
      }
    });

    // Vault Export Buttons
    document.getElementById('btn-export-csv')?.addEventListener('click', () => this.exportVault('csv'));
    document.getElementById('btn-export-txt')?.addEventListener('click', () => this.exportVault('txt'));
    document.getElementById('btn-export-json')?.addEventListener('click', () => this.exportVault('json'));
    document.getElementById('btn-clear-vault')?.addEventListener('click', () => this.clearVault());

    // Action buttons
    document.getElementById('btn-start-scrape')?.addEventListener('click', () => this.startScrape());
    document.getElementById('btn-start-enroll')?.addEventListener('click', () => this.startEnrollment());
    document.getElementById('btn-stop-all')?.addEventListener('click', () => this.stopAll());

    // License verify button
    document.getElementById('btn-verify-license')?.addEventListener('click', () => this.verifyLicense());

    // Check updates button
    document.getElementById('btn-check-updates')?.addEventListener('click', () => this.checkUpdates());

    // Sign out buttons (Account tab + sidebar footer)
    document.getElementById('btn-sign-out')?.addEventListener('click', () => this.signOut());
    const sideLogout = document.getElementById('btn-logout-sidebar');
    if (sideLogout) {
      sideLogout.addEventListener('click', () => this.signOut());
      sideLogout.addEventListener('mouseenter', () => { sideLogout.style.background = 'var(--color-danger)'; sideLogout.style.color = '#fff'; });
      sideLogout.addEventListener('mouseleave', () => { sideLogout.style.background = 'rgba(239,68,68,0.08)'; sideLogout.style.color = 'var(--color-danger)'; });
    }

    // License badge -> open plans/pricing page
    const licBadge = document.getElementById('license-time-badge');
    if (licBadge) {
      licBadge.addEventListener('click', () => this.openPlans());
      licBadge.addEventListener('mouseenter', () => { licBadge.style.filter = 'brightness(0.96)'; });
      licBadge.addEventListener('mouseleave', () => { licBadge.style.filter = 'none'; });
    }
    // Refresh the license countdown every minute
    setInterval(() => this.updateLicenseBadge(), 60000);

    // Save Settings button
    document.getElementById('btn-save-settings')?.addEventListener('click', () => this.saveSettings());

    // Udemy Connect buttons
    document.getElementById('btn-connect-udemy')?.addEventListener('click', () => this.connectUdemyCredentials());
    document.getElementById('btn-fetch-browser-cookies')?.addEventListener('click', () => this.connectUdemyBrowser());
    document.getElementById('btn-disconnect-udemy')?.addEventListener('click', () => this.disconnectUdemy());
  }

  switchTab(tabName) {
    this.currentTab = tabName;
    document.querySelectorAll('.nav-item').forEach(item => {
      item.classList.toggle('active', item.getAttribute('data-tab') === tabName);
    });

    document.querySelectorAll('.tab-view').forEach(view => {
      view.classList.toggle('active', view.id === `tab-${tabName}`);
    });

    if (tabName === 'analytics') {
      this.renderAnalyticsTab();
    } else if (tabName === 'vault') {
      this.loadVaultData();
    }
  }

  async initBackendState() {
    if (this.initialized) return;
    const data = await window.bridge.call('get_initial_state');
    if (!data) return;

    // ---- Auth gate: require a signed-in account before using the app ----
    const auth = data.auth || {};
    if (window.AuthUI) window.AuthUI.setHwid(data.hwid);
    if (!auth.authenticated) {
      this.initialized = false;
      if (window.AuthUI) window.AuthUI.open('login');
      return;
    }
    if (window.AuthUI) window.AuthUI.close();
    if (!auth.licensed) {
      window.toast && window.toast.show('Sign-in complete. Activate a license in Account & License to run the engine.', 'purple', 6000);
    }

    this.initialized = true;
    this.settings = data.settings || {};
    this.stats = data.stats || {};
    this.updateStatsUI();

    // Populate user profile
    if (data.license) {
      const emailEl = document.getElementById('sidebar-user-name');
      if (emailEl) emailEl.innerText = data.license.email || 'Pro User';
      const planEl = document.getElementById('sidebar-user-plan');
      if (planEl) planEl.innerText = data.license.plan || 'Activated';
      const accEmail = document.getElementById('acc-email');
      if (accEmail) accEmail.innerText = data.license.email || 'Registered User';
      const accPlan = document.getElementById('acc-plan');
      if (accPlan) accPlan.innerText = data.license.plan || 'Pro Lifetime';
      const accHwid = document.getElementById('acc-hwid');
      if (accHwid) accHwid.innerText = data.hwid || 'N/A';
    }

    // License countdown badge in the header
    this.license = data.license || {};
    this.licensed = !!(data.auth && data.auth.licensed);
    this.updateLicenseBadge();

    // Populate Udemy Account fields & status
    if (data.udemy_email) {
      const emailInput = document.getElementById('udemy-email');
      if (emailInput) emailInput.value = data.udemy_email;
    }
    if (data.udemy_password) {
      const passInput = document.getElementById('udemy-password');
      if (passInput) passInput.value = data.udemy_password;
    }
    this.updateUdemyConnectionStatus(data.udemy_connected, data.udemy_user);

    // Populate Settings Switches
    this.populateSettingsUI(data);

    // Populate recent logs
    if (data.recent_logs) {
      data.recent_logs.forEach(log => this.appendLog(log));
    }

    // Load admin-configured social / community buttons
    this.loadSocialButtons();
  }

  async loadSocialButtons() {
    try {
      const res = await window.bridge.call('get_promotion_buttons');
      const wrap = document.getElementById('social-buttons');
      if (!wrap) return;
      const buttons = (res && res.enabled && Array.isArray(res.buttons)) ? res.buttons : [];
      if (!buttons.length) { wrap.style.display = 'none'; wrap.innerHTML = ''; return; }

      const esc = (s) => String(s == null ? '' : s).replace(/[<>&"]/g, c => ({ '<':'&lt;','>':'&gt;','&':'&amp;','"':'&quot;' }[c]));
      let html = '<div style="font-size:10px;font-weight:700;letter-spacing:.9px;text-transform:uppercase;color:var(--text-dim);padding:0 6px 8px;">Community</div>';
      buttons.forEach(b => {
        const color = /^#[0-9a-fA-F]{3,8}$/.test(b.color || '') ? b.color : '#8b5cf6';
        const tc = /^#[0-9a-fA-F]{3,8}$/.test(b.text_color || '') ? b.text_color : '#ffffff';
        html += `<button class="social-btn" data-url="${esc(b.url)}" style="display:block;width:100%;margin-bottom:8px;padding:9px 12px;border:none;border-radius:10px;font-family:inherit;font-weight:600;font-size:12.5px;cursor:pointer;background:${color};color:${tc};transition:filter .15s;">${esc(b.label || 'Join')}</button>`;
      });
      wrap.innerHTML = html;
      wrap.style.display = '';
      wrap.querySelectorAll('.social-btn').forEach(btn => {
        btn.addEventListener('click', () => {
          const url = btn.getAttribute('data-url');
          if (url) window.bridge.call('open_external_url', url);
        });
        btn.addEventListener('mouseenter', () => btn.style.filter = 'brightness(1.08)');
        btn.addEventListener('mouseleave', () => btn.style.filter = 'none');
      });
    } catch (e) { /* non-fatal */ }
  }

  updateUdemyConnectionStatus(connected, userName) {
    this.udemyConnected = connected;
    const statusEl = document.getElementById('udemy-connection-status');
    const btnDisconnect = document.getElementById('btn-disconnect-udemy');
    
    if (statusEl) {
      if (connected) {
        statusEl.innerText = `Connected: ${userName || 'Active'}`;
        statusEl.style.background = 'rgba(16, 185, 129, 0.15)';
        statusEl.style.color = 'var(--color-success)';
      } else {
        statusEl.innerText = 'Disconnected';
        statusEl.style.background = 'rgba(239, 68, 68, 0.15)';
        statusEl.style.color = 'var(--color-danger)';
      }
    }

    if (btnDisconnect) {
      btnDisconnect.style.display = connected ? 'inline-flex' : 'none';
    }
  }

  startPolling() {
    setInterval(async () => {
      try {
        if (!this.initialized && window.pywebview && window.pywebview.api) {
          await this.initBackendState();
        }

        const update = await window.bridge.call('get_runtime_updates');
        if (!update) return;

        // 1. Drain new logs smoothly
        if (update.logs && update.logs.length > 0) {
          update.logs.forEach(log => this.appendLog(log));
        }

        // 2. Refresh stats & batch slots
        if (update.stats) {
          this.stats = update.stats;
          this.updateStatsUI();
        }

        // 3. Sync running flags with backend
        this.isScraping = !!update.is_scraping;
        this.isEnrolling = !!update.is_enrolling;

        // 4. Handle newly arrived scraped courses
        if (update.has_new_courses && update.courses) {
          this.courses = update.courses;
          this.filterCourses(document.getElementById('course-search')?.value || '');
          window.toast.show(`Scraping complete! Found ${update.courses.length} total courses.`, 'success');
          const statusText = document.getElementById('scrape-status-text');
          if (statusText) statusText.innerText = `Ready (${update.courses.length} courses found)`;
        }

        // 5. Update Analytics Data
        if (update.analytics) {
          this.analytics = update.analytics;
          if (this.currentTab === 'analytics') {
            this.renderAnalyticsTab();
          }
        }

        // 6. Update current processing course in dashboard
        if (update.current_course) {
          const titleEl = document.getElementById('curr-course-title');
          if (titleEl) titleEl.innerText = update.current_course.title || 'Processing...';
          const urlEl = document.getElementById('curr-course-url');
          if (urlEl) urlEl.innerText = update.current_course.url || '';
          const progEl = document.getElementById('curr-course-progress');
          if (progEl) progEl.innerText = `Course ${update.current_course.index} / ${update.current_course.total}`;
        }

        // 7. Handle enrollment completion
        if (update.enrollment_done) {
          this.isEnrolling = false;
          window.toast.show(`🎉 All enrollments completed! Total: ${this.stats.successfully_enrolled}`, 'success');
          const titleEl = document.getElementById('curr-course-title');
          if (titleEl) titleEl.innerText = 'All operations completed!';
        }

        // 8. Update scraping status badge
        const statusText = document.getElementById('scrape-status-text');
        if (statusText) {
          if (this.isScraping) {
            statusText.innerText = 'Scraping in progress...';
          } else if (this.isEnrolling) {
            statusText.innerText = 'Enrolling courses in batches...';
          } else if (this.courses.length > 0) {
            statusText.innerText = `Ready (${this.courses.length} courses found)`;
          } else {
            statusText.innerText = 'Idle';
          }
        }

        // 9. Update Udemy status if changed
        if (update.udemy_connected !== undefined) {
          this.updateUdemyConnectionStatus(update.udemy_connected, update.udemy_user);
        }

        // 10. Drive the live progress bar (scraping + enrollment)
        this.updateLiveProgress(update);
      } catch (e) {
        // Silently skip
      }
    }, 250);
  }

  openPlans() {
    window.bridge.call('open_external_url', 'https://ues.sohailsyed.com/#plans');
  }

  promptUpgrade(msg) {
    if (window.toast) window.toast.show((msg || 'Upgrade required.') + ' Opening plans…', 'error', 4500);
    this.openPlans();
  }

  _setLicBadge(text, tone) {
    const badge = document.getElementById('license-time-badge');
    const textEl = document.getElementById('license-time-text');
    if (!badge || !textEl) return;
    textEl.innerText = text;
    const tones = {
      ok:     ['var(--purple-light,#f5f3ff)', 'var(--purple-primary,#7c3aed)', 'var(--purple-border,#ddd6fe)'],
      warn:   ['rgba(217,119,6,0.10)', '#d97706', 'rgba(217,119,6,0.30)'],
      danger: ['rgba(220,38,38,0.10)', '#dc2626', 'rgba(220,38,38,0.32)'],
    };
    const [bg, c, b] = tones[tone] || tones.ok;
    badge.style.background = bg; badge.style.color = c; badge.style.borderColor = b;
    badge.style.display = 'inline-flex';
  }

  updateLicenseBadge() {
    const badge = document.getElementById('license-time-badge');
    if (!badge) return;
    const lic = this.license || {};
    const exp = lic.expires_at || '';
    const plan = lic.plan || '';
    const licensed = !!this.licensed;

    // Signed out or no license context at all -> hide badge
    if (!licensed && !exp) { badge.style.display = 'none'; return; }

    // Lifetime
    if (licensed && (/2099|never|lifetime/i.test(String(exp)) || /lifetime/i.test(plan))) {
      this._setLicBadge('Lifetime License', 'ok');
      return;
    }

    let expMs = Date.parse(String(exp).replace(' ', 'T'));
    const now = Date.now();

    if (isNaN(expMs)) {
      if (licensed) this._setLicBadge(plan ? (plan + ' · Active') : 'License Active', 'ok');
      else this._setLicBadge('No Active License', 'danger');
      return;
    }

    const diff = expMs - now;
    if (diff <= 0 || !licensed) {
      this._setLicBadge('License Expired — Renew', 'danger');
      if (!this._expiryPrompted) { this._expiryPrompted = true; this.promptUpgrade('Your license has expired.'); }
      return;
    }

    const days = Math.floor(diff / 86400000);
    const hours = Math.floor((diff % 86400000) / 3600000);
    if (days > 7)       this._setLicBadge(`${days} days left`, 'ok');
    else if (days >= 1) this._setLicBadge(`${days}d ${hours}h left`, 'warn');
    else                this._setLicBadge(`${hours}h left — Renew soon`, 'warn');
  }

  updateLiveProgress(update) {
    const card = document.getElementById('live-progress-card');
    const fill = document.getElementById('lp-fill');
    if (!card || !fill) return;
    const pctNum = document.getElementById('lp-percent-num');
    const phase = document.getElementById('curr-course-progress');
    const title = document.getElementById('curr-course-title');
    const url = document.getElementById('curr-course-url');
    const status = document.getElementById('scrape-status-text');
    const subL = document.getElementById('lp-sub-left');
    const subR = document.getElementById('lp-sub-right');

    const sp = update.scrape_progress || {};
    const ep = update.enroll_progress || {};
    let active = false, percent = 0;
    let phaseTxt = 'Engine Ready', titleTxt = 'Press "Run Scrapers" to discover 1,000+ free coupons';
    let urlTxt = 'https://www.udemy.com', statusTxt = 'Idle', left = 'Ready to start', right = '';

    if (update.is_scraping || sp.active) {
      active = true;
      percent = sp.percent || 0;
      phaseTxt = 'Scraping Sources';
      titleTxt = sp.current_site ? `Scraping ${sp.current_site}…` : 'Discovering free coupons across all sources';
      urlTxt = 'Multi-threaded scraping engine running';
      statusTxt = 'Scraping in progress';
      left = `${sp.done || 0} of ${sp.total || 0} sources completed`;
      right = `${sp.courses_found || 0} courses found`;
    } else if (update.is_enrolling || ep.active) {
      active = true;
      percent = ep.percent || 0;
      phaseTxt = 'Enrolling Courses';
      const cc = update.current_course;
      titleTxt = (cc && cc.title) ? cc.title : 'Batch enrolling into 100% OFF courses';
      urlTxt = (cc && cc.url) ? cc.url : 'Automated enrollment pipeline running';
      statusTxt = 'Enrolling in batches';
      left = `${ep.done || 0} of ${ep.total || 0} courses processed`;
      right = `${ep.enrolled || 0} enrolled`;
    } else {
      const found = (update.stats && update.stats.total_courses) || (this.courses ? this.courses.length : 0) || 0;
      if (found > 0) {
        percent = 100;
        phaseTxt = 'Completed';
        titleTxt = `Ready — ${found} courses in your catalog`;
        urlTxt = 'Press "Start Enrollment" to begin, or run scrapers again';
        statusTxt = `Ready (${found} found)`;
        left = 'Last run complete';
        right = `${found} courses`;
      }
    }

    card.classList.toggle('active', active);
    fill.style.width = percent + '%';
    if (pctNum) pctNum.innerText = percent;
    if (phase) phase.innerText = phaseTxt;
    if (title) title.innerText = titleTxt;
    if (url) url.innerText = urlTxt;
    if (status) status.innerText = statusTxt;
    if (subL) subL.innerText = left;
    if (subR) subR.innerText = right;
  }

  populateSettingsUI(data) {
    // Scraper sources
    const sourcesContainer = document.getElementById('sources-grid');
    if (sourcesContainer && data.available_sites) {
      sourcesContainer.innerHTML = '';
      data.available_sites.forEach(site => {
        const isChecked = this.settings.sites ? this.settings.sites[site] !== false : true;
        const card = document.createElement('div');
        card.className = 'source-card';
        card.innerHTML = `
          <div class="source-info">
            <div class="source-icon">${site.charAt(0)}</div>
            <div>
              <div class="source-name">${site}</div>
              <div class="source-status" id="status-${site.replace(/\s+/g, '')}">Active</div>
            </div>
          </div>
          <label class="switch">
            <input type="checkbox" id="site-${site.replace(/\s+/g, '')}" ${isChecked ? 'checked' : ''} data-site="${site}">
            <span class="slider"></span>
          </label>
        `;
        sourcesContainer.appendChild(card);
      });
    }

    // Language checkboxes
    const langContainer = document.getElementById('languages-grid');
    if (langContainer && data.available_languages) {
      langContainer.innerHTML = '';
      data.available_languages.forEach(lang => {
        const isChecked = this.settings.languages ? this.settings.languages[lang] !== false : true;
        const item = document.createElement('label');
        item.className = 'checkbox-card';
        item.innerHTML = `
          <input type="checkbox" data-lang="${lang}" ${isChecked ? 'checked' : ''}>
          <span>${lang}</span>
        `;
        langContainer.appendChild(item);
      });
    }
  }

  updateStatsUI() {
    const elEnrolled = document.getElementById('stat-enrolled');
    if (elEnrolled) elEnrolled.innerText = this.stats.successfully_enrolled || 0;
    
    const elSaved = document.getElementById('stat-saved');
    if (elSaved) elSaved.innerText = this.stats.amount_saved || '$0.00';
    
    const elAlready = document.getElementById('stat-already');
    if (elAlready) elAlready.innerText = this.stats.already_enrolled || 0;
    
    const elExpired = document.getElementById('stat-expired');
    if (elExpired) elExpired.innerText = `${this.stats.expired || 0} / ${this.stats.excluded || 0}`;

    // Update 5-slot visual batch queue
    const ready = this.stats.ready_count || 0;
    for (let i = 1; i <= 5; i++) {
      const slot = document.getElementById(`slot-${i}`);
      if (slot) {
        slot.classList.toggle('filled', i <= ready);
      }
    }
  }

  filterCourses(query) {
    const q = query.toLowerCase().trim();
    this.filteredCourses = this.courses.filter(c => {
      const matchCat = this.selectedCategory === 'all' || (c.category && c.category.toLowerCase() === this.selectedCategory.toLowerCase());
      const matchQuery = !q || (c.title && c.title.toLowerCase().includes(q)) || (c.category && c.category.toLowerCase().includes(q));
      return matchCat && matchQuery;
    });

    this.catalogPage = 1;
    this.renderCourseGrid();
  }

  renderCourseGrid() {
    const grid = document.getElementById('course-grid');
    if (!grid) return;
    grid.innerHTML = '';

    const total = this.filteredCourses.length;
    const maxPage = Math.ceil(total / this.catalogPageSize) || 1;
    if (this.catalogPage > maxPage) this.catalogPage = maxPage;
    if (this.catalogPage < 1) this.catalogPage = 1;

    const pageInfo = document.getElementById('catalog-page-info');
    const currPageEl = document.getElementById('catalog-current-page');
    const prevBtn = document.getElementById('btn-catalog-prev');
    const nextBtn = document.getElementById('btn-catalog-next');

    if (total === 0) {
      grid.innerHTML = '<div style="grid-column: 1/-1; text-align: center; color: #64748b; padding: 40px;">No courses found matching your criteria.</div>';
      if (pageInfo) pageInfo.innerText = 'Showing 0 courses';
      if (currPageEl) currPageEl.innerText = 'Page 1 of 1';
      if (prevBtn) prevBtn.disabled = true;
      if (nextBtn) nextBtn.disabled = true;
      return;
    }

    const startIdx = (this.catalogPage - 1) * this.catalogPageSize;
    const endIdx = Math.min(startIdx + this.catalogPageSize, total);
    const pageSlice = this.filteredCourses.slice(startIdx, endIdx);

    if (pageInfo) pageInfo.innerText = `Showing ${startIdx + 1}–${endIdx} of ${total} scraped courses`;
    if (currPageEl) currPageEl.innerText = `Page ${this.catalogPage} of ${maxPage}`;
    if (prevBtn) prevBtn.disabled = this.catalogPage <= 1;
    if (nextBtn) nextBtn.disabled = this.catalogPage >= maxPage;

    pageSlice.forEach(c => {
      const card = document.createElement('div');
      card.className = 'course-card';
      card.innerHTML = `
        <div>
          <div class="course-card-top">
            <span class="course-badge">100% OFF</span>
            <span style="font-size: 11px; color: #94a3b8; font-weight: 500;">${c.site || 'Udemy'}</span>
          </div>
          <div class="course-title" title="${c.title}">${c.title}</div>
          <div class="course-meta">
            <div class="course-meta-item">
              <svg viewBox="0 0 24 24" fill="none" stroke-width="2"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"></path></svg>
              <span>${c.category || 'Development'}</span>
            </div>
            <div class="course-meta-item">
              <svg viewBox="0 0 24 24" fill="none" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path></svg>
              <span>${c.language || 'English'}</span>
            </div>
          </div>
        </div>
        <div class="course-card-footer">
          <div>
            <span class="course-free-price">FREE</span>
          </div>
          <button class="btn btn-secondary" style="padding: 6px 12px; font-size: 12px;" onclick="window.bridge.call('open_external_url', '${c.url}')">
            View Link
          </button>
        </div>
      `;
      grid.appendChild(card);
    });
  }

  // ================= SCRAPED VAULT & DATABASE TAB =================
  async loadVaultData() {
    const res = await window.bridge.call('get_vault_data');
    if (res && res.courses) {
      this.vaultCourses = res.courses;
      this.filterVault();
    }
  }

  filterVault() {
    const q = document.getElementById('vault-search')?.value.toLowerCase().trim() || '';
    const cat = document.getElementById('vault-category-filter')?.value || 'all';
    const site = document.getElementById('vault-source-filter')?.value || 'all';

    this.vaultFiltered = this.vaultCourses.filter(item => {
      const matchCat = cat === 'all' || (item.category && item.category.toLowerCase() === cat.toLowerCase());
      const matchSite = site === 'all' || (item.site && item.site.toLowerCase() === site.toLowerCase());
      const matchQ = !q || (item.title && item.title.toLowerCase().includes(q)) || (item.coupon && item.coupon.toLowerCase().includes(q));
      return matchCat && matchSite && matchQ;
    });

    const badge = document.getElementById('vault-count-badge');
    if (badge) badge.innerText = `${this.vaultFiltered.length} Saved Courses`;

    this.vaultPage = 1;
    this.renderVaultTable();
  }

  renderVaultTable() {
    const tbody = document.getElementById('vault-table-body');
    if (!tbody) return;
    tbody.innerHTML = '';

    const total = this.vaultFiltered.length;
    const maxPage = Math.ceil(total / this.vaultPageSize) || 1;
    if (this.vaultPage > maxPage) this.vaultPage = maxPage;
    if (this.vaultPage < 1) this.vaultPage = 1;

    const pageInfo = document.getElementById('vault-page-info');
    const currPageEl = document.getElementById('vault-current-page');
    const prevBtn = document.getElementById('btn-vault-prev');
    const nextBtn = document.getElementById('btn-vault-next');

    if (pageInfo) pageInfo.innerText = total > 0 ? `Showing ${(this.vaultPage - 1) * this.vaultPageSize + 1}–${Math.min(this.vaultPage * this.vaultPageSize, total)} of ${total} courses` : 'Showing 0 courses';
    if (currPageEl) currPageEl.innerText = `Page ${this.vaultPage} of ${maxPage}`;
    if (prevBtn) prevBtn.disabled = this.vaultPage <= 1;
    if (nextBtn) nextBtn.disabled = this.vaultPage >= maxPage;

    if (total === 0) {
      tbody.innerHTML = `
        <tr>
          <td colspan="7" style="text-align: center; padding: 40px; color: var(--text-muted);">
            No archived courses found matching your filter criteria.
          </td>
        </tr>
      `;
      return;
    }

    const startIdx = (this.vaultPage - 1) * this.vaultPageSize;
    const pageSlice = this.vaultFiltered.slice(startIdx, startIdx + this.vaultPageSize);

    pageSlice.forEach((item, index) => {
      const tr = document.createElement('tr');
      tr.style.borderBottom = '1px solid var(--border-light)';
      tr.innerHTML = `
        <td style="padding: 12px 16px; color: var(--text-muted); font-size: 11.5px;">${startIdx + index + 1}</td>
        <td style="padding: 12px 16px; font-weight: 600; color: var(--text-darkblack); max-width: 320px; word-break: break-word;">
          ${item.title || 'Untitled Course'}
        </td>
        <td style="padding: 12px 16px;">
          <span style="font-size: 11px; padding: 3px 8px; border-radius: 4px; background: var(--purple-light); color: var(--purple-primary); font-weight: 600;">
            ${item.category || 'Development'}
          </span>
        </td>
        <td style="padding: 12px 16px; color: var(--text-muted); font-weight: 500;">
          ${item.site || 'Scraper'}
        </td>
        <td style="padding: 12px 16px;">
          <code style="font-family: monospace; font-size: 11px; padding: 2px 6px; background: var(--bg-main); border-radius: 4px; color: var(--text-darkblack); border: 1px solid var(--border-light);">
            ${item.coupon || 'DIRECT'}
          </code>
        </td>
        <td style="padding: 12px 16px; color: var(--text-muted); font-size: 11.5px;">
          ${item.date_scraped || 'Recent'}
        </td>
        <td style="padding: 12px 16px; text-align: center;">
          <button class="btn btn-secondary" style="padding: 4px 10px; font-size: 11px;" onclick="window.bridge.call('open_external_url', '${item.url}')">
            Open Link
          </button>
        </td>
      `;
      tbody.appendChild(tr);
    });
  }

  async exportVault(format) {
    const q = document.getElementById('vault-search')?.value.trim() || '';
    const cat = document.getElementById('vault-category-filter')?.value || 'all';
    const site = document.getElementById('vault-source-filter')?.value || 'all';

    window.toast.show(`Generating ${format.toUpperCase()} export...`, 'purple');
    const res = await window.bridge.call('export_vault_data', format, q, cat, site);
    if (res && res.success) {
      window.toast.show(res.message, 'success');
    } else {
      window.toast.show(res?.message || 'Export failed.', 'error');
    }
  }

  async clearVault() {
    if (!confirm('Are you sure you want to clear all historical courses in the vault?')) return;
    const res = await window.bridge.call('clear_vault_data');
    if (res && res.success) {
      window.toast.show('Vault cleared.', 'success');
      this.loadVaultData();
    }
  }

  appendLog(entry) {
    const box = document.getElementById('terminal-box');
    if (!box) return;
    const item = document.createElement('div');
    item.className = 'log-entry';
    item.innerHTML = `
      <span class="log-time">[${entry.time}]</span>
      <span class="log-level ${entry.level}">${entry.level}</span>
      <span class="log-msg">${entry.message}</span>
    `;
    box.appendChild(item);
    box.scrollTop = box.scrollHeight;
  }

  renderAnalyticsTab() {
    if (!this.analytics) return;

    const totalEl = document.getElementById('analytics-total-courses');
    if (totalEl) totalEl.innerText = (this.analytics.total_scraped || 0).toLocaleString();

    const valEl = document.getElementById('analytics-market-value');
    if (valEl) valEl.innerText = this.analytics.total_market_value || '$0.00';

    const topCatEl = document.getElementById('analytics-top-cat');
    if (topCatEl) topCatEl.innerText = this.analytics.top_category || 'Development';

    const srcEl = document.getElementById('analytics-active-sources');
    if (srcEl) srcEl.innerText = `${this.analytics.active_sources_count || 5} Sources`;

    if (window.UESCharts) {
      window.UESCharts.renderCategoryChart('analytics-canvas', this.analytics.categories);
      window.UESCharts.renderBreakdownList('analytics-sources-list', this.analytics.sources, this.analytics.total_scraped);
      window.UESCharts.renderBreakdownList('analytics-languages-list', this.analytics.languages, this.analytics.total_scraped);
    }
  }

  async startScrape() {
    if (this.isScraping) {
      window.toast.show('Scraping is already in progress...', 'purple');
      return;
    }

    let selectedSites = [];
    document.querySelectorAll('#sources-grid input:checked').forEach(input => {
      selectedSites.push(input.getAttribute('data-site'));
    });
    if (selectedSites.length === 0 && this.settings && this.settings.sites) {
      selectedSites = Object.keys(this.settings.sites).filter(s => this.settings.sites[s] !== false);
    }
    if (selectedSites.length === 0) {
      selectedSites = ["Discudemy", "Real Discount", "Courson", "IDownloadCoupons", "Course Joiner"];
    }
    
    this.isScraping = true;
    window.toast.show('Starting high-speed multi-threaded scrapers...', 'purple');
    const statusText = document.getElementById('scrape-status-text');
    if (statusText) statusText.innerText = 'Scraping in progress...';
    
    const res = await window.bridge.call('start_scraping', selectedSites);
    if (!res || !res.success) {
      if (res && res.message && res.message.includes('already in progress')) {
        // already running
      } else {
        window.toast.show(res?.message || 'Could not start scrapers.', 'error');
        this.isScraping = false;
        if (res && res.message && /licen/i.test(res.message)) this.promptUpgrade('A valid license is required.');
      }
    }
  }

  async startEnrollment() {
    if (this.courses.length === 0) {
      window.toast.show('No scraped courses found. Please run scrapers first!', 'error');
      return;
    }
    if (this.isEnrolling) {
      window.toast.show('Enrollment is already in progress...', 'purple');
      return;
    }

    if (!this.udemyConnected) {
      window.toast.show('⚠️ Please connect your Udemy Account in the Account tab first!', 'error');
      this.switchTab('account');
      return;
    }

    this.isEnrolling = true;
    window.toast.show('Starting automated enrollment pipeline...', 'purple');
    const res = await window.bridge.call('start_enrollment');
    if (!res || !res.success) {
      if (res && res.message && res.message.includes('already in progress')) {
        // normal
      } else {
        window.toast.show(res?.message || 'Error starting enrollment', 'error');
        this.isEnrolling = false;
        if (res && res.message && /licen/i.test(res.message)) this.promptUpgrade('A valid license is required.');
      }
    }
  }

  async connectUdemyCredentials() {
    const email = document.getElementById('udemy-email')?.value.trim();
    const password = document.getElementById('udemy-password')?.value.trim();

    if (!email || !password) {
      window.toast.show('Please enter both your Udemy email and password.', 'error');
      return;
    }

    window.toast.show('Connecting to Udemy with credentials...', 'purple');
    const res = await window.bridge.call('login_udemy_credentials', email, password);
    if (res?.success) {
      window.toast.show(res.message || 'Connected to Udemy successfully!', 'success');
      this.updateUdemyConnectionStatus(true, res.user);
      const update = await window.bridge.call('get_runtime_updates');
      if (update && update.stats) {
        this.stats = update.stats;
        this.updateStatsUI();
      }
    } else {
      window.toast.show(res?.message || 'Failed to connect to Udemy.', 'error');
      this.updateUdemyConnectionStatus(false);
    }
  }

  async connectUdemyBrowser() {
    window.toast.show('Extracting Udemy session from browser cookies...', 'purple');
    const res = await window.bridge.call('login_udemy_browser');
    if (res?.success) {
      window.toast.show(res.message || 'Connected to browser session successfully!', 'success');
      this.updateUdemyConnectionStatus(true, res.user);
      const update = await window.bridge.call('get_runtime_updates');
      if (update && update.stats) {
        this.stats = update.stats;
        this.updateStatsUI();
      }
    } else {
      window.toast.show(res?.message || 'Could not extract browser cookies. Please use Email/Password login.', 'error');
      this.updateUdemyConnectionStatus(false);
    }
  }

  async disconnectUdemy() {
    window.toast.show('Disconnecting Udemy account...', 'purple');
    const res = await window.bridge.call('logout_udemy');
    if (res?.success) {
      window.toast.show('Udemy account disconnected.', 'success');
      this.updateUdemyConnectionStatus(false);
      const emailInput = document.getElementById('udemy-email');
      const passInput = document.getElementById('udemy-password');
      if (emailInput) emailInput.value = '';
      if (passInput) passInput.value = '';
    } else {
      window.toast.show(res?.message || 'Error disconnecting account.', 'error');
    }
  }

  async stopAll() {
    await window.bridge.call('stop_all');
    this.isScraping = false;
    this.isEnrolling = false;
    window.toast.show('All processes stopped.', 'purple');
    const statusText = document.getElementById('scrape-status-text');
    if (statusText) statusText.innerText = 'Stopped';
  }

  async verifyLicense() {
    const key = document.getElementById('license-input')?.value.trim();
    if (!key) {
      window.toast.show('Please enter a valid license key.', 'error');
      return;
    }
    window.toast.show('Verifying license with server...', 'purple');
    const res = await window.bridge.call('verify_license', key);
    if (res?.success) {
      window.toast.show('License activated successfully!', 'success');
      this.initialized = false;
      this.initBackendState();
    } else {
      window.toast.show(res?.message || 'License verification failed.', 'error');
    }
  }

  async signOut() {
    await window.bridge.call('auth_logout');
    window.toast.show('Signed out successfully.', 'purple');
    this.initialized = false;
    // Reset the sidebar identity so stale details don't linger behind the modal
    const nameEl = document.getElementById('sidebar-user-name');
    if (nameEl) nameEl.innerText = 'Guest';
    const planEl = document.getElementById('sidebar-user-plan');
    if (planEl) planEl.innerText = 'Not signed in';
    if (window.AuthUI) {
      window.AuthUI.open('login');
    } else {
      window.location.reload();
    }
  }

  async checkUpdates() {
    window.toast.show('Checking for updates...', 'purple');
    const res = await window.bridge.call('check_updates');
    if (res?.update_available) {
      window.toast.show(`Update available: v${res.latest_version}`, 'success');
    } else {
      window.toast.show('You are running the latest version.', 'success');
    }
  }

  async saveSettings() {
    const sites = {};
    document.querySelectorAll('#sources-grid input').forEach(input => {
      sites[input.getAttribute('data-site')] = input.checked;
    });

    const languages = {};
    document.querySelectorAll('#languages-grid input').forEach(input => {
      languages[input.getAttribute('data-lang')] = input.checked;
    });

    const res = await window.bridge.call('save_settings', { sites, languages });
    if (res?.success) {
      window.toast.show('Settings saved successfully!', 'success');
    } else {
      window.toast.show('Failed to save settings.', 'error');
    }
  }
}

// Global bootstrap
window.addEventListener('DOMContentLoaded', () => {
  window.app = new App();
});
