DuoHacker

Best free-to-use Duolingo farming tool!

// ==UserScript==
// @name         DuoHacker
// @name:zh-CN   DuoHacker — 免费 Duolingo 农场工具
// @name:ja      DuoHacker — 無料の Duolingo ファーミングツール
// @name:es      DuoHacker — Herramienta gratuita para farmear en Duolingo
// @name:ru      DuoHacker — Бесплатный инструмент для фарминга Duolingo
// @name:pt-BR   DuoHacker — Melhor ferramenta gratuita para farmar no Duolingo
// @description  Best free-to-use Duolingo farming tool!
// @description:zh-CN  免费且易用的 Duolingo 农场工具!
// @description:ja     無料で使える Duolingo のファーミングツールです!
// @description:es     ¡La mejor herramienta gratuita para farmear en Duolingo!
// @description:ru     Лучший бесплатный инструмент для фарминга в Duolingo!
// @description:pt-BR  A melhor ferramenta gratuita para farmar no Duolingo!
// @namespace    https://irylisvps.vercel.app
// @version      1.0.1
// @author       DuoHacker Community
// @match        https://*.duolingo.com/*
// @icon         https://github.com/pillowslua/images/blob/main/Hacklingo.png?raw=true
// @grant        none
// @license      MIT
// ==/UserScript==


const VERSION = "1.0";
const DELAY = 300;
const MAX_THREADS = 5;

var jwt, defaultHeaders, userInfo, sub;
let isRunning = false;
let currentTheme = localStorage.getItem('duofarmer_theme') || 'dark';
let hasJoined = localStorage.getItem('duofarmer_joined') === 'true';
let activeThreads = [];
let totalEarned = { xp: 0, gems: 0, streak: 0 };
let farmingStats = { sessions: 0, errors: 0, startTime: null };

const initInterface = () => {
  const containerHTML = `
  <div id="_backdrop"></div>
  <div id="_container" class="theme-${currentTheme}">
    <!-- Header with TwiskGPT inspired design -->
    <div id="_header">
      <div class="_header_content">
        <div class="_logo_section">
          <div class="_logo">
            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.9-.09z"/><path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"/><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0"/><path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/></svg>
          </div>
          <div class="_title_section">
            <h1>DuoHacker PRO</h1>
            <span class="_subtitle">BEST Duolingo Farming Tool</span>
          </div>
        </div>
        <div class="_header_actions">
          <button id="_minimize_btn" class="_header_btn" title="Minimize">-</button>
          <button id="_settings_btn" class="_header_btn" title="Settings">&#9881;</button>
          <button id="_close_btn" class="_header_btn _close" title="Close">x</button>
        </div>
      </div>
    </div>

    <!-- Join Discord section -->
    <div id="_join_section" class="_section ${hasJoined ? '_collapsed' : ''}">
      <div class="_section_header" onclick="toggleSection('_join_section')">
        <div class="_section_title">
          <span class="_section_icon">
            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="12" x="2" y="6" rx="2"/><circle cx="12" cy="12" r="2"/><path d="M6 12c.5-1 3-3 6-3s5.5 2 6 3"/><path d="M6 12c.5 1 3 3 6 3s5.5-2 6-3"/></svg>
          </span>
          <span>Join Our Community</span>
        </div>
        <div class="_section_status">
          <span id="_join_status" class="${hasJoined ? '_status_success' : '_status_error'}">
            ${hasJoined ? '&#10003; Joined' : '&#9888; Required'}
          </span>
          <span class="_chevron ${hasJoined ? '_rotated' : ''}">&#9660;</span>
        </div>
      </div>
      <div class="_section_content" ${hasJoined ? 'style="display:none"' : ''}>
        <div class="_input_container">
          <button id="_join_btn" class="_primary_btn">
            <span class="_btn_content">
              <span class="_btn_icon">
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"/></svg>
              </span>
              <span class="_btn_text">Join Discord</span>
            </span>
          </button>
        </div>
        <div class="_help_text">
          Join our Discord server for updates and support!
        </div>
      </div>
    </div>

    <!-- Main content (hidden until joined) -->
    <div id="_main_content" ${hasJoined ? '' : 'style="display:none"' }>

      <!-- User info section -->
      <div id="_user_section" class="_section">
        <div class="_section_header">
          <div class="_section_title">
            <span class="_section_icon">
              <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
            </span>
            <span>Account Overview</span>
          </div>
          <button id="_refresh_btn" class="_icon_btn" title="Refresh data">&#8635;</button>
        </div>
        <div class="_section_content">
          <div class="_stats_grid">
            <div class="_stat_card">
              <div class="_stat_icon">
                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
              </div>
              <div class="_stat_content">
                <div class="_stat_label">Username</div>
                <div class="_stat_value" id="_username">Loading...</div>
              </div>
            </div>
            <div class="_stat_card">
              <div class="_stat_icon">&#127758;</div>
              <div class="_stat_content">
                <div class="_stat_label">Languages</div>
                <div class="_stat_value">
                  <span id="_from_lang">--</span> -> <span id="_learning_lang">--</span>
                </div>
              </div>
            </div>
            <div class="_stat_card">
              <div class="_stat_icon">
                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"/><path d="m10 17 5-5-5-5"/></svg>
              </div>
              <div class="_stat_content">
                <div class="_stat_label">Streak</div>
                <div class="_stat_value" id="_current_streak">0</div>
              </div>
            </div>
            <div class="_stat_card">
              <div class="_stat_icon">
                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/></svg>
              </div>
              <div class="_stat_content">
                <div class="_stat_label">Gems</div>
                <div class="_stat_value" id="_current_gems">0</div>
              </div>
            </div>
            <div class="_stat_card">
              <div class="_stat_icon">
                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" x2="12" y1="2" y2="22"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>
              </div>
              <div class="_stat_content">
                <div class="_stat_label">Total XP</div>
                <div class="_stat_value" id="_current_xp">0</div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- Farming control section -->
      <div id="_farming_section" class="_section">
        <div class="_section_header">
          <div class="_section_title">
            <span class="_section_icon">
              <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 22 16 17"/><path d="M14 16.5V5.5"/><path d="M15 18.5c-1.4 1-3.1 1.5-4.7 1-1.3.4-2.6-.2-3.5-1.1-.8-.8-1.3-2-1-3.3.6-2.5 4-3.8 3.8-6.1-.3-1.6-1.4-2.8-2.9-3.3"/><path d="M20.97 21.5c.2-1.1-.3-2.5-1-3.5-.7-1-2-1.6-3.5-1.1-2.7.5-3.1 2.2-3.7 4.2-.3 1.3.2 2.6 1.1 3.5.9.9 3.7 1.3 5.1.4"/><path d="M3 5.5 5 17"/><path d="M18.5 16H20c.3 0 .5-.2.5-.5V6.3c0-.3-.2-.5-.5-.5h-1.2c-.3 0-.5.2-.5.5v.3c0 .3.2.5.5.5h.5v8"/></svg>
            </span>
            <span>Farming Controls</span>
          </div>
          <div class="_thread_indicator">
            <span class="_thread_count">Threads: <strong id="_active_threads">0</strong>/${MAX_THREADS}</span>
          </div>
        </div>
        <div class="_section_content">
          <div class="_farming_controls">
            <div class="_control_row">
              <select id="_farming_mode" class="_modern_select">
                <option value="xp_multi">&#9889; Multi-threaded XP Farming</option>
                <option value="gem_multi">&#128142; Multi-threaded Gem Farming</option>
                <option value="streak_repair">&#128295; Streak Repair (Single)</option>
                <option value="streak_farm">&#128293; Streak Farming (Single)</option>
                <option value="mixed_farming">&#127919; Mixed Farming (All types)</option>
              </select>
              <div class="_thread_control">
                <label>Threads:</label>
                <input type="range" id="_thread_slider" min="1" max="${MAX_THREADS}" value="3" class="_slider">
                <span id="_thread_display">3</span>
              </div>
            </div>
            <div class="_control_row">
              <button id="_start_farming" class="_primary_btn _large">
                <span class="_btn_content">
                  <span class="_btn_icon">&#9654;</span>
                  <span class="_btn_text">Start Farming</span>
                </span>
              </button>
              <button id="_stop_farming" class="_danger_btn _large" style="display:none">
                <span class="_btn_content">
                  <span class="_btn_icon">&#9209;</span>
                  <span class="_btn_text">Stop Farming</span>
                </span>
              </button>
              <button id="_pause_farming" class="_secondary_btn" style="display:none">
                <span class="_btn_content">
                  <span class="_btn_icon">&#9192;</span>
                  <span class="_btn_text">Pause</span>
                </span>
              </button>
            </div>
          </div>
        </div>
      </div>

      <!-- Statistics section -->
      <div id="_stats_section" class="_section">
        <div class="_section_header">
          <div class="_section_title">
            <span class="_section_icon">
              <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3v18h18"/><path d="M18.7 8l-5.1 5.2-2.8-2.9L7 14.1"/></svg>
            </span>
            <span>Live Statistics</span>
          </div>
          <button id="_reset_stats" class="_icon_btn" title="Reset statistics">&#8635;</button>
        </div>
        <div class="_section_content">
          <div class="_stats_grid _live_stats">
            <div class="_stat_card _earned">
              <div class="_stat_icon">&#9889;</div>
              <div class="_stat_content">
                <div class="_stat_label">XP Earned</div>
                <div class="_stat_value" id="_earned_xp">0</div>
              </div>
            </div>
            <div class="_stat_card _earned">
              <div class="_stat_icon">&#128142;</div>
              <div class="_stat_content">
                <div class="_stat_label">Gems Earned</div>
                <div class="_stat_value" id="_earned_gems">0</div>
              </div>
            </div>
            <div class="_stat_card _earned">
              <div class="_stat_icon">&#128293;</div>
              <div class="_stat_content">
                <div class="_stat_label">Streak Gained</div>
                <div class="_stat_value" id="_earned_streak">0</div>
              </div>
            </div>
            <div class="_stat_card">
              <div class="_stat_icon">&#127919;</div>
              <div class="_stat_content">
                <div class="_stat_label">Success Rate</div>
                <div class="_stat_value" id="_success_rate">100%</div>
              </div>
            </div>
          </div>
          <div class="_progress_section">
            <div class="_progress_header">
              <span>Farming Progress</span>
              <span id="_farming_time">00:00:00</span>
            </div>
            <div class="_thread_progress">
              <div id="_thread_bars"></div>
            </div>
          </div>
        </div>
      </div>

      <!-- Console output -->
      <div id="_console_section" class="_section">
        <div class="_section_header">
          <div class="_section_title">
            <span class="_section_icon">
              <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 17 10 11 4 5"/><line x1="12" x2="20" y1="19" y2="19"/></svg>
            </span>
            <span>Console Output</span>
          </div>
          <div class="_console_controls">
            <button id="_clear_console" class="_icon_btn" title="Clear console">&#128465;</button>
            <button id="_auto_scroll" class="_icon_btn _active" title="Auto scroll">&#128220;</button>
          </div>
        </div>
        <div class="_section_content">
          <div id="_console_output" class="_console">
            <div class="_console_line _info">
              <span class="_timestamp">[${new Date().toLocaleTimeString()}]</span>
              <span class="_message">DuoNexus v${VERSION} initialized</span>
            </div>
            <div class="_console_line _info">
              <span class="_timestamp">[${new Date().toLocaleTimeString()}]</span>
              <span class="_message">Multi-threading engine ready</span>
            </div>
          </div>
        </div>
      </div>

    </div>

    <!-- Settings Modal -->
    <div id="_settings_modal" class="_modal" style="display:none">
      <div class="_modal_overlay"></div>
      <div class="_modal_container">
        <div class="_modal_header">
          <h2>Settings & Preferences</h2>
          <button id="_close_modal" class="_icon_btn">x</button>
        </div>
        <div class="_modal_content">
          <div class="_setting_group">
            <h3>&#127912; Appearance</h3>
            <div class="_theme_selector">
              <button class="_theme_option ${currentTheme === 'dark' ? '_active' : ''}" data-theme="dark">
                <span class="_theme_preview _dark"></span>
                <span>Dark Mode</span>
              </button>
              <button class="_theme_option ${currentTheme === 'light' ? '_active' : ''}" data-theme="light">
                <span class="_theme_preview _light"></span>
                <span>Light Mode</span>
              </button>
            </div>
          </div>

          <div class="_setting_group">
            <h3>&#9889; Performance</h3>
            <div class="_setting_item">
              <label>Request Delay (ms)</label>
              <input type="range" id="_delay_slider" min="100" max="1000" value="${DELAY}" class="_slider">
              <span id="_delay_value">${DELAY}ms</span>
            </div>
            <div class="_setting_item">
              <label>Auto-pause on errors</label>
              <input type="checkbox" id="_auto_pause" class="_checkbox" checked>
            </div>
          </div>

          <div class="_setting_group">
            <h3>&#128279; Quick Actions</h3>
            <div class="_action_buttons">
              <a href="https://www.duolingo.com/errors/404.html" target="_blank" class="_action_btn">
                &#128196; Blank Page
              </a>
              <button id="_export_stats" class="_action_btn">
                &#128202; Export Stats
              </button>
              <button id="_backup_settings" class="_action_btn">
                &#128190; Backup Settings
              </button>
            </div>
          </div>

          <div class="_setting_group">
            <h3>&#8505; About</h3>
            <div class="_about_section">
              <p><strong>DuoHacker v${VERSION}</strong></p>
              <p>Join our community for FREE SUPPORT 24/7 and PRO version</p>
              <p>Developer: <strong>tw1sk</strong></p>
              <p>Free-to-use best farming tool!</p>
              <div class="_social_links">
                <a href="https://discord.gg/Gvmd7deFtS" target="_blank" class="_social_btn">&#128172; Discord</a>
                <a href="https://irylisvps.vercel.app/" target="_blank" class="_social_btn">&#128230; Website</a>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- Footer -->
    <div id="_footer">
      <div class="_footer_content">
        <span>&#169; 2025 DuoHacker by <strong>tw1sk</strong></span>
        <span class="_version">v${VERSION}</span>
      </div>
    </div>
  </div>

  <!-- DuoHX GPT -->
  <div id="_floating_container">
    <div id="_floating_btn" class="theme-${currentTheme}" title="Open DuoNexus">
      <div class="_btn_ripple"></div>
      <div class="_btn_icon">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.9-.09z"/><path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"/><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0"/><path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/></svg>
      </div>
    </div>
  </div>
`;

  const style = document.createElement("style");
  style.innerHTML = `
    /* CSS Variables for theming */
    :root {
      --animation-duration: 0.2s;
      --animation-ease: cubic-bezier(0.4, 0, 0.2, 1);
      --border-radius-sm: 6px;
      --border-radius-md: 12px;
      --border-radius-lg: 20px;
      --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
      --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.15);
      --shadow-lg: 0 10px 40px rgba(0, 0, 0, 0.2);
      --gradient-primary: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      --gradient-success: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
      --gradient-danger: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
    }

    /* Dark Theme */
    .theme-dark {
      --bg-primary: #0d1117;
      --bg-secondary: #161b22;
      --bg-tertiary: #21262d;
      --bg-quaternary: #30363d;
      --text-primary: #f0f6fc;
      --text-secondary: #8b949e;
      --text-tertiary: #6e7681;
      --border-primary: #30363d;
      --border-secondary: #21262d;
      --accent-primary: #58a6ff;
      --accent-secondary: #1f6feb;
      --success-color: #3fb950;
      --error-color: #f85149;
      --warning-color: #d29922;
    }

    /* Light Theme */
    .theme-light {
      --bg-primary: #ffffff;
      --bg-secondary: #f6f8fa;
      --bg-tertiary: #eaeef2;
      --bg-quaternary: #d0d7de;
      --text-primary: #24292f;
      --text-secondary: #656d76;
      --text-tertiary: #8c959f;
      --border-primary: #d0d7de;
      --border-secondary: #eaeef2;
      --accent-primary: #0969da;
      --accent-secondary: #0550ae;
      --success-color: #1a7f37;
      --error-color: #cf222e;
      --warning-color: #9a6700;
    }

    /* Reset and base styles */
    * {
      box-sizing: border-box;
    }

    /* Container */
    #_container {
      position: fixed;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 95vw;
      max-width: 1200px;
      max-height: 90vh;
      background: var(--bg-primary);
      border: 1px solid var(--border-primary);
      border-radius: var(--border-radius-lg);
      box-shadow: var(--shadow-lg);
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;
      color: var(--text-primary);
      z-index: 9999;
      display: flex;
      flex-direction: column;
      overflow: hidden;
      animation: containerSlideIn var(--animation-duration) var(--animation-ease);
    }

    @keyframes containerSlideIn {
      from {
        opacity: 0;
        transform: translate(-50%, -60%);
      }
      to {
        opacity: 1;
        transform: translate(-50%, -50%);
      }
    }

    /* Backdrop */
    #_backdrop {
      position: fixed;
      top: 0;
      left: 0;
      width: 100vw;
      height: 100vh;
      background: rgba(0, 0, 0, 0.6);
      backdrop-filter: blur(8px);
      z-index: 9998;
      animation: backdropFadeIn var(--animation-duration) var(--animation-ease);
    }

    @keyframes backdropFadeIn {
      from { opacity: 0; }
      to { opacity: 1; }
    }

    /* Header */
    #_header {
      background: var(--bg-secondary);
      border-bottom: 1px solid var(--border-primary);
      padding: 16px 20px;
    }

    ._header_content {
      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    ._logo_section {
      display: flex;
      align-items: center;
      gap: 12px;
    }

    ._logo {
      width: 40px;
      height: 40px;
      background: var(--gradient-primary);
      border-radius: 12px;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 20px;
      animation: logoSpin 2s ease-in-out infinite;
    }

    @keyframes logoSpin {
      0%, 100% { transform: rotate(0deg); }
      50% { transform: rotate(180deg); }
    }

    ._title_section h1 {
      margin: 0;
      font-size: 20px;
      font-weight: 600;
      background: var(--gradient-primary);
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
      background-clip: text;
    }

    ._subtitle {
      font-size: 12px;
      color: var(--text-secondary);
      margin: 0;
    }

    ._header_actions {
      display: flex;
      gap: 8px;
    }

    ._header_btn {
      width: 32px;
      height: 32px;
      border: none;
      background: transparent;
      color: var(--text-secondary);
      border-radius: var(--border-radius-sm);
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 18px;
      transition: all var(--animation-duration) var(--animation-ease);
    }

    ._header_btn:hover {
      background: var(--bg-tertiary);
      color: var(--text-primary);
      transform: scale(1.1);
    }

    ._header_btn._close:hover {
      background: var(--error-color);
      color: white;
    }

    /* Sections */
    ._section {
      border-bottom: 1px solid var(--border-secondary);
    }

    ._section_header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 16px 20px;
      cursor: pointer;
      background: var(--bg-secondary);
      transition: background var(--animation-duration) var(--animation-ease);
    }

    ._section_header:hover {
      background: var(--bg-tertiary);
    }

    ._section_title {
      display: flex;
      align-items: center;
      gap: 12px;
      font-weight: 600;
      font-size: 16px;
    }

    ._section_icon {
      font-size: 20px;
      display: flex;
      align-items: center;
    }

    ._section_icon svg {
      width: 20px;
      height: 20px;
    }

    ._section_status {
      display: flex;
      align-items: center;
      gap: 8px;
    }

    ._status_success {
      color: var(--success-color);
      font-weight: 600;
    }

    ._status_error {
      color: var(--error-color);
      font-weight: 600;
    }

    ._chevron {
      transition: transform var(--animation-duration) var(--animation-ease);
      color: var(--text-tertiary);
    }

    ._chevron._rotated {
      transform: rotate(180deg);
    }

    ._section._collapsed ._section_content {
      display: none;
    }

    ._section_content {
      padding: 20px;
      background: var(--bg-primary);
    }

    /* Input elements */
    ._input_container {
      display: flex;
      gap: 12px;
      margin-bottom: 12px;
    }

    ._modern_input, ._modern_select {
      flex: 1;
      padding: 12px 16px;
      background: var(--bg-secondary);
      border: 1px solid var(--border-primary);
      border-radius: var(--border-radius-md);
      color: var(--text-primary);
      font-size: 14px;
      transition: all var(--animation-duration) var(--animation-ease);
      font-family: inherit;
    }

    ._modern_input:focus, ._modern_select:focus {
      outline: none;
      border-color: var(--accent-primary);
      box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.1);
    }

    ._modern_select {
      cursor: pointer;
    }

    /* Buttons */
    ._primary_btn, ._secondary_btn, ._danger_btn {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      padding: 10px 16px;
      border: none;
      border-radius: var(--border-radius-md);
      font-size: 14px;
      font-weight: 500;
      cursor: pointer;
      transition: all var(--animation-duration) var(--animation-ease);
      text-decoration: none;
      white-space: nowrap;
    }

    ._primary_btn {
      background: var(--accent-primary);
      color: white;
    }

    ._primary_btn:hover {
      background: var(--accent-secondary);
      transform: translateY(-2px);
      box-shadow: var(--shadow-md);
    }

    ._secondary_btn {
      background: var(--bg-tertiary);
      color: var(--text-primary);
      border: 1px solid var(--border-primary);
    }

    ._secondary_btn:hover {
      background: var(--bg-quaternary);
      transform: translateY(-1px);
    }

    ._danger_btn {
      background: var(--error-color);
      color: white;
    }

    ._danger_btn:hover {
      background: #d73a49;
      transform: translateY(-2px);
      box-shadow: var(--shadow-md);
    }

    ._large {
      padding: 14px 28px;
      font-size: 16px;
      font-weight: 600;
    }

    ._btn_content {
      display: flex;
      align-items: center;
      gap: 8px;
    }

    ._btn_icon {
      font-size: 16px;
    }

    ._icon_btn {
      width: 36px;
      height: 36px;
      border: none;
      background: transparent;
      color: var(--text-secondary);
      border-radius: var(--border-radius-sm);
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 16px;
      transition: all var(--animation-duration) var(--animation-ease);
    }

    ._icon_btn:hover {
      background: var(--bg-tertiary);
      color: var(--text-primary);
      transform: scale(1.1);
    }

    ._icon_btn._active {
      background: var(--accent-primary);
      color: white;
    }

    /* Stats grid */
    ._stats_grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
      gap: 16px;
    }

    ._stat_card {
      background: var(--bg-secondary);
      border: 1px solid var(--border-primary);
      border-radius: var(--border-radius-md);
      padding: 16px;
      display: flex;
      align-items: center;
      gap: 12px;
      transition: all var(--animation-duration) var(--animation-ease);
    }

    ._stat_card:hover {
      transform: translateY(-2px);
      box-shadow: var(--shadow-sm);
      border-color: var(--accent-primary);
    }

    ._stat_card._earned {
      background: linear-gradient(135deg, var(--bg-secondary) 0%, var(--bg-tertiary) 100%);
      border-color: var(--success-color);
    }

    ._stat_icon {
      width: 40px;
      height: 40px;
      background: var(--gradient-primary);
      border-radius: 10px;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 20px;
      flex-shrink: 0;
    }

    ._stat_icon svg {
      width: 24px;
      height: 24px;
    }

    ._stat_content {
      flex: 1;
    }

    ._stat_label {
      font-size: 12px;
      color: var(--text-secondary);
      margin-bottom: 4px;
      font-weight: 500;
    }

    ._stat_value {
      font-size: 18px;
      font-weight: 600;
      color: var(--text-primary);
    }

    /* Farming controls */
    ._farming_controls {
      display: flex;
      flex-direction: column;
      gap: 16px;
    }

    ._control_row {
      display: flex;
      align-items: center;
      gap: 16px;
    }

    ._thread_control {
      display: flex;
      align-items: center;
      gap: 8px;
      font-size: 14px;
    }

    ._thread_indicator {
      background: var(--bg-tertiary);
      padding: 6px 12px;
      border-radius: var(--border-radius-sm);
      font-size: 12px;
      color: var(--text-secondary);
    }

    ._slider {
      width: 80px;
      height: 4px;
      border-radius: 2px;
      background: var(--bg-tertiary);
      outline: none;
      cursor: pointer;
    }

    ._slider::-webkit-slider-thumb {
      appearance: none;
      width: 16px;
      height: 16px;
      border-radius: 50%;
      background: var(--accent-primary);
      cursor: pointer;
      box-shadow: var(--shadow-sm);
    }

    /* Progress bars */
    ._progress_section {
      margin-top: 16px;
    }

    ._progress_header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 12px;
      font-size: 14px;
      font-weight: 600;
    }

    ._thread_progress {
      background: var(--bg-secondary);
      border-radius: var(--border-radius-sm);
      padding: 12px;
    }

    ._thread_bar {
      display: flex;
      align-items: center;
      gap: 8px;
      margin-bottom: 8px;
      font-size: 12px;
    }

    ._thread_bar:last-child {
      margin-bottom: 0;
    }

    ._thread_id {
      width: 60px;
      color: var(--text-secondary);
    }

    ._thread_progress_bar {
      flex: 1;
      height: 6px;
      background: var(--bg-tertiary);
      border-radius: 3px;
      overflow: hidden;
    }

    ._thread_progress_fill {
      height: 100%;
      background: var(--gradient-success);
      transition: width 0.5s ease;
      border-radius: 3px;
    }

    ._thread_status {
      width: 80px;
      text-align: right;
      color: var(--text-tertiary);
      font-size: 11px;
    }

    /* Console */
    ._console {
      height: 200px;
      background: var(--bg-secondary);
      border: 1px solid var(--border-primary);
      border-radius: var(--border-radius-md);
      padding: 12px;
      overflow-y: auto;
      font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
      font-size: 13px;
      line-height: 1.4;
    }

    ._console_line {
      display: flex;
      gap: 8px;
      margin-bottom: 2px;
      align-items: flex-start;
    }

    ._timestamp {
      color: var(--text-tertiary);
      font-weight: 500;
      flex-shrink: 0;
    }

    ._message {
      color: var(--text-primary);
    }

    ._console_line._success ._message {
      color: var(--success-color);
    }

    ._console_line._error ._message {
      color: var(--error-color);
    }

    ._console_line._warning ._message {
      color: var(--warning-color);
    }

    ._console_line._info ._message {
      color: var(--accent-primary);
    }

    ._console_controls {
      display: flex;
      gap: 4px;
    }

    /* Settings Modal */
    ._modal {
      position: fixed;
      top: 0;
      left: 0;
      width: 100vw;
      height: 100vh;
      z-index: 10000;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    ._modal_overlay {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: rgba(0, 0, 0, 0.6);
      backdrop-filter: blur(8px);
    }

    ._modal_container {
      position: relative;
      width: 90%;
      max-width: 600px;
      max-height: 80vh;
      background: var(--bg-primary);
      border: 1px solid var(--border-primary);
      border-radius: var(--border-radius-lg);
      box-shadow: var(--shadow-lg);
      overflow: hidden;
      animation: modalSlideIn var(--animation-duration) var(--animation-ease);
    }

    @keyframes modalSlideIn {
      from {
        opacity: 0;
        transform: scale(0.9) translateY(-20px);
      }
      to {
        opacity: 1;
        transform: scale(1) translateY(0);
      }
    }

    ._modal_header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 20px;
      background: var(--bg-secondary);
      border-bottom: 1px solid var(--border-primary);
    }

    ._modal_header h2 {
      margin: 0;
      font-size: 18px;
      font-weight: 600;
    }

    ._modal_content {
      padding: 20px;
      overflow-y: auto;
      max-height: calc(80vh - 80px);
    }

    ._setting_group {
      margin-bottom: 24px;
    }

    ._setting_group:last-child {
      margin-bottom: 0;
    }

    ._setting_group h3 {
      margin: 0 0 16px 0;
      font-size: 16px;
      font-weight: 600;
      display: flex;
      align-items: center;
      gap: 8px;
    }

    ._theme_selector {
      display: flex;
      gap: 12px;
    }

    ._theme_option {
      flex: 1;
      padding: 16px;
      background: var(--bg-secondary);
      border: 2px solid var(--border-primary);
      border-radius: var(--border-radius-md);
      cursor: pointer;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 8px;
      transition: all var(--animation-duration) var(--animation-ease);
      color: var(--text-primary);
    }

    ._theme_option:hover {
      border-color: var(--accent-primary);
      transform: translateY(-2px);
    }

    ._theme_option._active {
      border-color: var(--accent-primary);
      background: var(--accent-primary);
      color: white;
    }

    ._theme_preview {
      width: 32px;
      height: 20px;
      border-radius: 4px;
      position: relative;
    }

    ._theme_preview._dark {
      background: linear-gradient(to bottom, #0d1117 0%, #161b22 50%, #21262d 100%);
    }

    ._theme_preview._light {
      background: linear-gradient(to bottom, #ffffff 0%, #f6f8fa 50%, #eaeef2 100%);
    }

    ._setting_item {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 12px 0;
      border-bottom: 1px solid var(--border-secondary);
    }

    ._setting_item:last-child {
      border-bottom: none;
    }

    ._setting_item label {
      font-weight: 500;
      color: var(--text-primary);
    }

    ._checkbox {
      width: 18px;
      height: 18px;
      accent-color: var(--accent-primary);
    }

    ._action_buttons {
      display: flex;
      flex-direction: column;
      gap: 8px;
    }

    ._action_btn {
      display: flex;
      align-items: center;
      gap: 8px;
      padding: 12px 16px;
      background: var(--bg-secondary);
      border: 1px solid var(--border-primary);
      border-radius: var(--border-radius-md);
      color: var(--text-primary);
      text-decoration: none;
      font-size: 14px;
      transition: all var(--animation-duration) var(--animation-ease);
      cursor: pointer;
    }

    ._action_btn:hover {
      background: var(--bg-tertiary);
      border-color: var(--accent-primary);
    }

    ._about_section {
      padding: 16px;
      background: var(--bg-secondary);
      border-radius: var(--border-radius-md);
      font-size: 14px;
      line-height: 1.6;
    }

    ._about_section p {
      margin: 8px 0;
    }

    ._social_links {
      display: flex;
      gap: 8px;
      margin-top: 12px;
    }

    ._social_btn {
      padding: 8px 12px;
      background: var(--accent-primary);
      color: white;
      text-decoration: none;
      border-radius: var(--border-radius-sm);
      font-size: 12px;
      font-weight: 500;
      transition: all var(--animation-duration) var(--animation-ease);
    }

    ._social_btn:hover {
      background: var(--accent-secondary);
      transform: translateY(-2px);
    }

    /* Footer */
    #_footer {
      background: var(--bg-secondary);
      border-top: 1px solid var(--border-primary);
      padding: 16px 20px;
    }

    ._footer_content {
      display: flex;
      justify-content: space-between;
      align-items: center;
      font-size: 12px;
      color: var(--text-secondary);
    }

    ._version {
      background: var(--bg-tertiary);
      padding: 4px 8px;
      border-radius: var(--border-radius-sm);
      font-weight: 600;
    }

    /* Floating Button - Claude.ai inspired */
    #_floating_container {
      position: fixed;
      bottom: 24px;
      right: 24px;
      z-index: 10001;
    }

    #_floating_btn {
      position: relative;
      width: 56px;
      height: 56px;
      background: var(--accent-primary);
      border-radius: 50%;
      box-shadow: var(--shadow-lg);
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      transition: all var(--animation-duration) var(--animation-ease);
      overflow: hidden;
    }

    #_floating_btn:hover {
      transform: scale(1.05);
      box-shadow: 0 8px 25px rgba(88, 166, 255, 0.4);
    }

    #_floating_btn:active {
      transform: scale(0.95);
    }

    ._btn_ripple {
      position: absolute;
      border-radius: 50%;
      transform: scale(0);
      animation: ripple 0.6s linear;
      background-color: rgba(255, 255, 255, 0.7);
    }

    @keyframes ripple {
      to {
        transform: scale(4);
        opacity: 0;
      }
    }

    ._btn_icon {
      font-size: 24px;
      z-index: 1;
      transition: transform var(--animation-duration) var(--animation-ease);
    }

    #_floating_btn:hover ._btn_icon {
      transform: rotate(180deg);
    }

    /* Responsive Design */
    @media (max-width: 768px) {
      #_container {
        width: 98vw;
        max-height: 95vh;
      }

      ._stats_grid {
        grid-template-columns: 1fr 1fr;
      }

      ._control_row {
        flex-direction: column;
        align-items: stretch;
      }

      ._thread_control {
        justify-content: center;
      }

      ._modal_container {
        width: 95%;
        margin: 20px;
      }
    }

    @media (max-width: 480px) {
      ._stats_grid {
        grid-template-columns: 1fr;
      }

      #_floating_btn {
        width: 48px;
        height: 48px;
        bottom: 16px;
        right: 16px;
      }

      ._btn_icon {
        font-size: 20px;
      }
    }

    /* Utility Classes */
    .hidden {
      display: none !important;
    }

    .loading {
      opacity: 0.6;
      pointer-events: none;
    }

    /* Scrollbar Styling */
    ::-webkit-scrollbar {
      width: 8px;
    }

    ::-webkit-scrollbar-track {
      background: var(--bg-tertiary);
      border-radius: 4px;
    }

    ::-webkit-scrollbar-thumb {
      background: var(--border-primary);
      border-radius: 4px;
      transition: background var(--animation-duration) var(--animation-ease);
    }

    ::-webkit-scrollbar-thumb:hover {
      background: var(--text-tertiary);
    }

    /* Help text */
    ._help_text {
      font-size: 12px;
      color: var(--text-tertiary);
      line-height: 1.4;
    }

    ._help_text strong {
      color: var(--accent-primary);
      font-weight: 600;
    }

    /* Loading animation */
    @keyframes pulse {
      0%, 100% {
        opacity: 1;
      }
      50% {
        opacity: 0.5;
      }
    }

    ._loading {
      animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
    }
  `;

  document.head.appendChild(style);

  const container = document.createElement("div");
  container.innerHTML = containerHTML;
  document.body.appendChild(container);
};

// Multi-threading worker class
class FarmingWorker {
  constructor(id, type, delay = DELAY) {
    this.id = id;
    this.type = type;
    this.delay = delay;
    this.isActive = false;
    this.stats = { requests: 0, successes: 0, errors: 0 };
    this.progressElement = null;
  }

  async start() {
    this.isActive = true;
    this.createProgressBar();
    logToConsole(`Thread ${this.id} started (${this.type})`, 'success');

    while (this.isActive && isRunning) {
      try {
        await this.doWork();
        this.stats.requests++;
        this.stats.successes++;
        this.updateProgress();
        await delay(this.delay + Math.random() * 200); // Add some randomization
      } catch (error) {
        this.stats.errors++;
        logToConsole(`Thread ${this.id} error: ${error.message}`, 'error');
        await delay(this.delay * 2); // Back off on error
      }
    }

    logToConsole(`Thread ${this.id} stopped`, 'info');
  }

  async doWork() {
    switch (this.type) {
      case 'xp':
        return await this.farmXP();
      case 'gem':
        return await this.farmGem();
      default:
        throw new Error(`Unknown work type: ${this.type}`);
    }
  }

  async farmXP() {
    const response = await farmXpOnce();
    if (response.ok) {
      const data = await response.json();
      const earned = data?.awardedXp || 0;
      totalEarned.xp += earned;
      updateEarnedStats();
      logToConsole(`Thread ${this.id} earned ${earned} XP`, 'success');
      return earned;
    }
    throw new Error(`XP farming failed: ${response.status}`);
  }

  async farmGem() {
    const response = await farmGemOnce();
    if (response.ok) {
      totalEarned.gems += 30;
      updateEarnedStats();
      logToConsole(`Thread ${this.id} earned 30 gems`, 'success');
      return 30;
    }
    throw new Error(`Gem farming failed: ${response.status}`);
  }

  stop() {
    this.isActive = false;
    if (this.progressElement) {
      this.progressElement.remove();
    }
  }

  createProgressBar() {
    const container = document.getElementById('_thread_bars');
    if (!container) return;

    this.progressElement = document.createElement('div');
    this.progressElement.className = '_thread_bar';
    this.progressElement.innerHTML = `
      <div class="_thread_id">Thread ${this.id}</div>
      <div class="_thread_progress_bar">
        <div class="_thread_progress_fill" style="width: 0%"></div>
      </div>
      <div class="_thread_status">Starting...</div>
    `;
    container.appendChild(this.progressElement);
  }

  updateProgress() {
    if (!this.progressElement) return;

    const successRate = this.stats.requests > 0 ?
      (this.stats.successes / this.stats.requests * 100) : 100;

    const fillElement = this.progressElement.querySelector('._thread_progress_fill');
    const statusElement = this.progressElement.querySelector('._thread_status');

    fillElement.style.width = `${Math.min(successRate, 100)}%`;
    statusElement.textContent = `${this.stats.successes}/${this.stats.requests}`;

    // Update fill color based on success rate
    if (successRate >= 90) {
      fillElement.style.background = 'var(--gradient-success)';
    } else if (successRate >= 70) {
      fillElement.style.background = 'var(--warning-color)';
    } else {
      fillElement.style.background = 'var(--error-color)';
    }
  }
}

// Utility functions
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

const logToConsole = (message, type = 'info') => {
  const console = document.getElementById('_console_output');
  if (!console) return;

  const timestamp = new Date().toLocaleTimeString();
  const line = document.createElement('div');
  line.className = `_console_line _${type}`;
  line.innerHTML = `
    <span class="_timestamp">[${timestamp}]</span>
    <span class="_message">${message}</span>
  `;

  console.appendChild(line);

  // Auto scroll if enabled
  const autoScroll = document.getElementById('_auto_scroll');
  if (autoScroll && autoScroll.classList.contains('_active')) {
    console.scrollTop = console.scrollHeight;
  }

  // Keep only last 100 lines
  while (console.children.length > 100) {
    console.removeChild(console.firstChild);
  }
};

const updateEarnedStats = () => {
  const elements = {
    xp: document.getElementById('_earned_xp'),
    gems: document.getElementById('_earned_gems'),
    streak: document.getElementById('_earned_streak')
  };

  if (elements.xp) elements.xp.textContent = totalEarned.xp.toLocaleString();
  if (elements.gems) elements.gems.textContent = totalEarned.gems.toLocaleString();
  if (elements.streak) elements.streak.textContent = totalEarned.streak;

  // Update success rate
  const successRate = farmingStats.sessions > 0 ?
    ((farmingStats.sessions - farmingStats.errors) / farmingStats.sessions * 100) : 100;
  const successElement = document.getElementById('_success_rate');
  if (successElement) {
    successElement.textContent = `${successRate.toFixed(1)}%`;
  }

  // Update user info if available
  if (userInfo) {
    userInfo.totalXp += totalEarned.xp;
    userInfo.gems += totalEarned.gems;
    userInfo.streak += totalEarned.streak;
    updateUserInfo();
  }
};

const updateFarmingTime = () => {
  if (!farmingStats.startTime) return;

  const elapsed = Date.now() - farmingStats.startTime;
  const hours = Math.floor(elapsed / 3600000);
  const minutes = Math.floor((elapsed % 3600000) / 60000);
  const seconds = Math.floor((elapsed % 60000) / 1000);

  const timeElement = document.getElementById('_farming_time');
  if (timeElement) {
    timeElement.textContent = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
  }
};

// Interface management
const setInterfaceVisible = (visible) => {
  const container = document.getElementById("_container");
  const backdrop = document.getElementById("_backdrop");

  if (container && backdrop) {
    container.style.display = visible ? "flex" : "none";
    backdrop.style.display = visible ? "block" : "none";
  }
};

const isInterfaceVisible = () => {
  const container = document.getElementById("_container");
  return container && container.style.display !== "none";
};

const toggleInterface = () => {
  setInterfaceVisible(!isInterfaceVisible());
};

const toggleSection = (sectionId) => {
  const section = document.getElementById(sectionId);
  if (section) {
    section.classList.toggle('_collapsed');
    const chevron = section.querySelector('._chevron');
    if (chevron) {
      chevron.classList.toggle('_rotated');
    }
  }
};

// Theme management
const applyTheme = (theme) => {
  currentTheme = theme;
  localStorage.setItem('duofarmer_theme', theme);

  const elements = [
    document.getElementById("_container"),
    document.getElementById("_floating_btn")
  ];

  elements.forEach(el => {
    if (el) {
      el.className = el.className.replace(/theme-\w+/, `theme-${theme}`);
    }
  });

  // Update theme selector
  document.querySelectorAll('._theme_option').forEach(btn => {
    btn.classList.toggle('_active', btn.dataset.theme === theme);
  });
};

// Event listeners
const addEventListeners = () => {
  // Floating button
  document.getElementById('_floating_btn')?.addEventListener('click', (e) => {
    // Create ripple effect
    const button = e.currentTarget;
    const ripple = button.querySelector('._btn_ripple');
    const rect = button.getBoundingClientRect();
    const size = Math.max(rect.width, rect.height);
    const x = e.clientX - rect.left - size / 2;
    const y = e.clientY - rect.top - size / 2;

    ripple.style.width = ripple.style.height = size + 'px';
    ripple.style.left = x + 'px';
    ripple.style.top = y + 'px';
    ripple.style.transform = 'scale(0)';
    ripple.style.opacity = '0.7';

    setTimeout(() => {
      ripple.style.transform = 'scale(4)';
      ripple.style.opacity = '0';
    }, 10);

    toggleInterface();
  });

  // Header controls
  document.getElementById('_minimize_btn')?.addEventListener('click', () => {
    setInterfaceVisible(false);
  });

  document.getElementById('_close_btn')?.addEventListener('click', () => {
    if (isRunning) {
      if (confirm('Farming is active. Are you sure you want to close?')) {
        stopFarming();
        setInterfaceVisible(false);
      }
    } else {
      setInterfaceVisible(false);
    }
  });

  document.getElementById('_settings_btn')?.addEventListener('click', () => {
    document.getElementById('_settings_modal').style.display = 'flex';
  });

  // Join button
  document.getElementById('_join_btn')?.addEventListener('click', () => {
    window.open('https://discord.gg/Gvmd7deFtS', '_blank');
    localStorage.setItem('duofarmer_joined', 'true');
    hasJoined = true;
    toggleSection('_join_section');
    document.getElementById('_join_status').textContent = '&#10003; Joined';
    document.getElementById('_join_status').className = '_status_success';
    document.getElementById('_main_content').style.display = 'block';
    // Initialize in background
    initializeFarming();
  });

  // Farming controls
  document.getElementById('_start_farming')?.addEventListener('click', startFarming);
  document.getElementById('_stop_farming')?.addEventListener('click', stopFarming);
  document.getElementById('_pause_farming')?.addEventListener('click', pauseFarming);

  // Thread slider
  const slider = document.getElementById('_thread_slider');
  const display = document.getElementById('_thread_display');
  slider?.addEventListener('input', (e) => {
    if (display) display.textContent = e.target.value;
    updateActiveThreadsDisplay();
  });

  // Refresh button
  document.getElementById('_refresh_btn')?.addEventListener('click', async () => {
    const button = document.getElementById('_refresh_btn');
    if (button) button.classList.add('_loading');

    await refreshUserData();

    if (button) button.classList.remove('_loading');
  });

  // Console controls
  document.getElementById('_clear_console')?.addEventListener('click', () => {
    const console = document.getElementById('_console_output');
    if (console) console.innerHTML = '';
  });

  document.getElementById('_auto_scroll')?.addEventListener('click', (e) => {
    e.currentTarget.classList.toggle('_active');
  });

  // Settings modal
  document.getElementById('_close_modal')?.addEventListener('click', () => {
    document.getElementById('_settings_modal').style.display = 'none';
  });

  document.getElementById('_settings_modal')?.addEventListener('click', (e) => {
    if (e.target.classList.contains('_modal_overlay')) {
      document.getElementById('_settings_modal').style.display = 'none';
    }
  });

  // Theme selection
  document.querySelectorAll('._theme_option').forEach(btn => {
    btn.addEventListener('click', () => {
      applyTheme(btn.dataset.theme);
    });
  });

  // Settings controls
  document.getElementById('_delay_slider')?.addEventListener('input', (e) => {
    const value = e.target.value;
    document.getElementById('_delay_value').textContent = `${value}ms`;
  });

  // Stats reset
  document.getElementById('_reset_stats')?.addEventListener('click', resetStats);

  // Export stats
  document.getElementById('_export_stats')?.addEventListener('click', exportStats);
};

// Farming functions
const startFarming = async () => {
  if (isRunning) return;

  const mode = document.getElementById('_farming_mode')?.value;
  const threadCount = parseInt(document.getElementById('_thread_slider')?.value || '3');

  isRunning = true;
  farmingStats.startTime = Date.now();
  farmingStats.sessions = 0;
  farmingStats.errors = 0;

  // Update UI
  document.getElementById('_start_farming').style.display = 'none';
  document.getElementById('_stop_farming').style.display = 'inline-flex';
  document.getElementById('_pause_farming').style.display = 'inline-flex';

  logToConsole(`Starting ${mode} with ${threadCount} threads`, 'success');

  // Start farming timer
  const timer = setInterval(updateFarmingTime, 1000);

  try {
    switch (mode) {
      case 'xp_multi':
        await startMultiThreadedFarming('xp', threadCount);
        break;
      case 'gem_multi':
        await startMultiThreadedFarming('gem', threadCount);
        break;
      case 'mixed_farming':
        await startMixedFarming(threadCount);
        break;
      case 'streak_repair':
        await repairStreak();
        break;
      case 'streak_farm':
        await farmStreakLoop();
        break;
      default:
        logToConsole(`Unknown farming mode: ${mode}`, 'error');
    }
  } catch (error) {
    logToConsole(`Farming error: ${error.message}`, 'error');
  } finally {
    clearInterval(timer);
  }
};

const stopFarming = () => {
  if (!isRunning) return;

  isRunning = false;

  // Stop all threads
  activeThreads.forEach(thread => thread.stop());
  activeThreads = [];

  // Update UI
  document.getElementById('_start_farming').style.display = 'inline-flex';
  document.getElementById('_stop_farming').style.display = 'none';
  document.getElementById('_pause_farming').style.display = 'none';

  // Clear progress bars
  const threadBars = document.getElementById('_thread_bars');
  if (threadBars) threadBars.innerHTML = '';

  updateActiveThreadsDisplay();
  logToConsole('Farming stopped', 'info');
};

const pauseFarming = () => {
  // Toggle pause state
  const button = document.getElementById('_pause_farming');
  const isPaused = button.textContent.includes('Resume');

  if (isPaused) {
    // Resume farming
    activeThreads.forEach(thread => thread.isActive = true);
    button.innerHTML = '<span class="_btn_content"><span class="_btn_icon">&#9192;</span><span class="_btn_text">Pause</span></span>';
    logToConsole('Farming resumed', 'info');
  } else {
    // Pause farming
    activeThreads.forEach(thread => thread.isActive = false);
    button.innerHTML = '<span class="_btn_content"><span class="_btn_icon">&#9654;</span><span class="_btn_text">Resume</span></span>';
    logToConsole('Farming paused', 'warning');
  }
};

const startMultiThreadedFarming = async (type, threadCount) => {
  activeThreads = [];

  for (let i = 1; i <= threadCount; i++) {
    const worker = new FarmingWorker(i, type);
    activeThreads.push(worker);

    // Start thread with slight delay to avoid rate limiting
    setTimeout(() => {
      if (isRunning) worker.start();
    }, i * 100);
  }

  updateActiveThreadsDisplay();

  // Wait for all threads to complete (they run until stopped)
  await new Promise(resolve => {
    const checkInterval = setInterval(() => {
      if (!isRunning || activeThreads.every(thread => !thread.isActive)) {
        clearInterval(checkInterval);
        resolve();
      }
    }, 1000);
  });
};

const startMixedFarming = async (threadCount) => {
  activeThreads = [];
  const types = ['xp', 'gem'];

  for (let i = 1; i <= threadCount; i++) {
    const type = types[(i - 1) % types.length];
    const worker = new FarmingWorker(i, type);
    activeThreads.push(worker);

    setTimeout(() => {
      if (isRunning) worker.start();
    }, i * 150);
  }

  updateActiveThreadsDisplay();

  await new Promise(resolve => {
    const checkInterval = setInterval(() => {
      if (!isRunning || activeThreads.every(thread => !thread.isActive)) {
        clearInterval(checkInterval);
        resolve();
      }
    }, 1000);
  });
};

const updateActiveThreadsDisplay = () => {
  const display = document.getElementById('_active_threads');
  if (display) {
    display.textContent = activeThreads.filter(thread => thread.isActive).length;
  }
};

// Original farming functions (adapted for multi-threading)
const getJwtToken = () => {
  const cookies = document.cookie.split(";");
  for (let cookie of cookies) {
    cookie = cookie.trim();
    if (cookie.startsWith("jwt_token=")) {
      return cookie.substring("jwt_token=".length);
    }
  }
  return null;
};

const decodeJwtToken = (token) => {
  const base64Url = token.split(".")[1];
  const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
  const jsonPayload = decodeURIComponent(
    atob(base64)
      .split("")
      .map(c => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2))
      .join("")
  );
  return JSON.parse(jsonPayload);
};

const formatHeaders = (jwt) => ({
  "Content-Type": "application/json",
  Authorization: "Bearer " + jwt,
  "User-Agent": navigator.userAgent,
});

const getUserInfo = async (sub) => {
  const userInfoUrl = `https://www.duolingo.com/2017-06-30/users/${sub}?fields=id,username,fromLanguage,learningLanguage,streak,totalXp,level,numFollowers,numFollowing,gems,creationDate,streakData`;
  const response = await fetch(userInfoUrl, {
    method: "GET",
    headers: defaultHeaders,
  });
  return await response.json();
};

const sendRequestWithDefaultHeaders = async ({ url, payload, headers = {}, method = "GET" }) => {
  const mergedHeaders = { ...defaultHeaders, ...headers };
  return await fetch(url, {
    method,
    headers: mergedHeaders,
    body: payload ? JSON.stringify(payload) : undefined,
  });
};

const farmXpOnce = async () => {
  const startTime = Math.floor(Date.now() / 1000);
  const fromLanguage = userInfo.fromLanguage;
  const completeUrl = `https://stories.duolingo.com/api2/stories/en-${fromLanguage}-the-passport/complete`;

  const payload = {
    awardXp: true,
    isFeaturedStoryInPracticeHub: false,
    completedBonusChallenge: true,
    mode: "READ",
    isV2Redo: false,
    isV2Story: false,
    isLegendaryMode: true,
    masterVersion: false,
    maxScore: 0,
    numHintsUsed: 0,
    score: 0,
    startTime: startTime,
    fromLanguage: fromLanguage,
    learningLanguage: "en",
    hasXpBoost: false,
    happyHourBonusXp: 449,
  };

  return await sendRequestWithDefaultHeaders({
    url: completeUrl,
    payload: payload,
    method: "POST",
  });
};

const farmGemOnce = async () => {
  const idReward = "SKILL_COMPLETION_BALANCED-dd2495f4_d44e_3fc3_8ac8_94e2191506f0-2-GEMS";
  const patchUrl = `https://www.duolingo.com/2017-06-30/users/${sub}/rewards/${idReward}`;

  const patchData = {
    consumed: true,
    learningLanguage: userInfo.learningLanguage,
    fromLanguage: userInfo.fromLanguage,
  };

  return await sendRequestWithDefaultHeaders({
    url: patchUrl,
    payload: patchData,
    method: "PATCH",
  });
};

const repairStreak = async () => {
  logToConsole('Starting streak repair...', 'info');

  try {
    if (!userInfo.streakData?.currentStreak) {
      logToConsole('No streak to repair!', 'error');
      return;
    }

    const startStreakDate = userInfo.streakData.currentStreak.startDate;
    const endStreakDate = userInfo.streakData.currentStreak.endDate;
    const startStreakTimestamp = Math.floor(new Date(startStreakDate).getTime() / 1000);
    const endStreakTimestamp = Math.floor(new Date(endStreakDate).getTime() / 1000);
    const expectedStreak = Math.floor((endStreakTimestamp - startStreakTimestamp) / (60 * 60 * 24)) + 1;

    if (expectedStreak > userInfo.streak) {
      logToConsole(`Found ${expectedStreak - userInfo.streak} frozen days. Repairing...`, 'warning');

      let currentTimestamp = Math.floor(Date.now() / 1000);
      for (let i = 0; i < expectedStreak && isRunning; i++) {
        await farmSessionOnce(currentTimestamp, currentTimestamp + 60);
        currentTimestamp -= 86400;
        logToConsole(`Repaired day ${i + 1}/${expectedStreak}`, 'info');
        await delay(DELAY);
      }

      const updatedUser = await getUserInfo(sub);
      if (updatedUser.streak >= expectedStreak) {
        logToConsole(`Streak repair completed! New streak: ${updatedUser.streak}`, 'success');
        userInfo = updatedUser;
        totalEarned.streak += (updatedUser.streak - userInfo.streak);
        updateUserInfo();
        updateEarnedStats();
      }
    } else {
      logToConsole('No frozen streak detected', 'info');
    }
  } catch (error) {
    logToConsole(`Streak repair failed: ${error.message}`, 'error');
  } finally {
    stopFarming();
  }
};

const farmStreakLoop = async () => {
  logToConsole('Starting streak farming...', 'info');

  const hasStreak = !!userInfo.streakData?.currentStreak;
  const startStreakDate = hasStreak ? userInfo.streakData.currentStreak.startDate : new Date();
  const startFarmStreakTimestamp = Math.floor(new Date(startStreakDate).getTime() / 1000);
  let currentTimestamp = hasStreak ? startFarmStreakTimestamp - 86400 : startFarmStreakTimestamp;

  while (isRunning) {
    try {
      await farmSessionOnce(currentTimestamp, currentTimestamp + 60);
      currentTimestamp -= 86400;
      totalEarned.streak++;
      userInfo.streak++;
      updateUserInfo();
      updateEarnedStats();
      logToConsole(`Streak increased to ${userInfo.streak}`, 'success');
      await delay(DELAY);
    } catch (error) {
      logToConsole(`Streak farming error: ${error.message}`, 'error');
      await delay(DELAY * 2);
    }
  }
};

const farmSessionOnce = async (startTime, endTime) => {
  const sessionPayload = {
    challengeTypes: [
      "assist", "characterIntro", "characterMatch", "characterPuzzle", "characterSelect",
      "characterTrace", "characterWrite", "completeReverseTranslation", "definition",
      "dialogue", "extendedMatch", "extendedListenMatch", "form", "freeResponse",
      "gapFill", "judge", "listen", "listenComplete", "listenMatch", "match", "name",
      "listenComprehension", "listenIsolation", "listenSpeak", "listenTap",
      "orderTapComplete", "partialListen", "partialReverseTranslate", "patternTapComplete",
      "radioBinary", "radioImageSelect", "radioListenMatch", "radioListenRecognize",
      "radioSelect", "readComprehension", "reverseAssist", "sameDifferent", "select",
      "selectPronunciation", "selectTranscription", "svgPuzzle", "syllableTap",
      "syllableListenTap", "speak", "tapCloze", "tapClozeTable", "tapComplete",
      "tapCompleteTable", "tapDescribe", "translate", "transliterate",
      "transliterationAssist", "typeCloze", "typeClozeTable", "typeComplete",
      "typeCompleteTable", "writeComprehension",
    ],
    fromLanguage: userInfo.fromLanguage,
    isFinalLevel: false,
    isV2: true,
    juicy: true,
    learningLanguage: userInfo.learningLanguage,
    smartTipsVersion: 2,
    type: "GLOBAL_PRACTICE",
  };

  const sessionRes = await sendRequestWithDefaultHeaders({
    url: "https://www.duolingo.com/2017-06-30/sessions",
    payload: sessionPayload,
    method: "POST",
  });

  const sessionData = await sessionRes.json();

  const updateSessionPayload = {
    ...sessionData,
    heartsLeft: 0,
    startTime: startTime,
    enableBonusPoints: false,
    endTime: endTime,
    failed: false,
    maxInLessonStreak: 9,
    shouldLearnThings: true,
  };

  const updateRes = await sendRequestWithDefaultHeaders({
    url: `https://www.duolingo.com/2017-06-30/sessions/${sessionData.id}`,
    payload: updateSessionPayload,
    method: "PUT",
  });

  return await updateRes.json();
};

// UI update functions
const updateUserInfo = () => {
  if (!userInfo) return;

  const elements = {
    username: document.getElementById('_username'),
    fromLang: document.getElementById('_from_lang'),
    learningLang: document.getElementById('_learning_lang'),
    currentStreak: document.getElementById('_current_streak'),
    currentGems: document.getElementById('_current_gems'),
    currentXp: document.getElementById('_current_xp')
  };

  if (elements.username) elements.username.textContent = userInfo.username;
  if (elements.fromLang) elements.fromLang.textContent = userInfo.fromLanguage;
  if (elements.learningLang) elements.learningLang.textContent = userInfo.learningLanguage;
  if (elements.currentStreak) elements.currentStreak.textContent = userInfo.streak?.toLocaleString() || '0';
  if (elements.currentGems) elements.currentGems.textContent = userInfo.gems?.toLocaleString() || '0';
  if (elements.currentXp) elements.currentXp.textContent = userInfo.totalXp?.toLocaleString() || '0';
};

const refreshUserData = async () => {
  if (!sub || !defaultHeaders) return;

  try {
    logToConsole('Refreshing user data...', 'info');
    userInfo = await getUserInfo(sub);
    updateUserInfo();
    logToConsole('User data refreshed successfully', 'success');
  } catch (error) {
    logToConsole(`Failed to refresh user data: ${error.message}`, 'error');
  }
};

const resetStats = () => {
  totalEarned = { xp: 0, gems: 0, streak: 0 };
  farmingStats = { sessions: 0, errors: 0, startTime: null };
  updateEarnedStats();
  logToConsole('Statistics reset', 'info');
};

const exportStats = () => {
  const stats = {
    totalEarned,
    farmingStats,
    userInfo: userInfo ? {
      username: userInfo.username,
      streak: userInfo.streak,
      gems: userInfo.gems,
      totalXp: userInfo.totalXp
    } : null,
    exportDate: new Date().toISOString(),
    version: VERSION
  };

  const blob = new Blob([JSON.stringify(stats, null, 2)], { type: 'application/json' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = `duofarmer-stats-${new Date().toISOString().split('T')[0]}.json`;
  a.click();
  URL.revokeObjectURL(url);

  logToConsole('Statistics exported successfully', 'success');
};

// Initialization
const initializeFarming = async () => {
  try {
    jwt = getJwtToken();
    if (!jwt) {
      logToConsole('Please login to Duolingo and reload the page', 'error');
      return false;
    }

    defaultHeaders = formatHeaders(jwt);
    const decodedJwt = decodeJwtToken(jwt);
    sub = decodedJwt.sub;

    logToConsole('Loading user information...', 'info');
    userInfo = await getUserInfo(sub);

    if (userInfo && userInfo.username) {
      updateUserInfo();
      logToConsole(`Welcome ${userInfo.username}! Ready to farm.`, 'success');
      return true;
    } else {
      logToConsole('Failed to load user information', 'error');
      return false;
    }
  } catch (error) {
    logToConsole(`Initialization error: ${error.message}`, 'error');
    return false;
  }
};

// Main initialization
(async () => {
  try {
    // Initialize interface
    initInterface();
    setInterfaceVisible(false);

    // Apply saved theme
    applyTheme(currentTheme);

    // Add event listeners
    addEventListeners();

    if (hasJoined) {
      // Initialize in background without blocking
      initializeFarming();
    }

    logToConsole('DuoNexus initialized successfully', 'success');
    logToConsole('Created by tw1sk - Discord: @tw1sk', 'info');

  } catch (error) {
    console.error('Initialization failed:', error);
  }
})();