← back to Handbag Auth Nextjs

auction-viewer/index.html

1437 lines

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>LUXVAULT Auction Data Viewer</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
  <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
  <style>
    :root {
      --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      --bg-color: #f5f7fa;
      --card-bg: #ffffff;
      --text-primary: #333333;
      --text-secondary: #666666;
      --border-color: #e0e0e0;
      --shadow-sm: 0 2px 8px rgba(0,0,0,0.1);
      --shadow-md: 0 10px 30px rgba(0,0,0,0.2);
      --shadow-lg: 0 20px 60px rgba(0,0,0,0.3);
      --success: #10b981;
      --warning: #f59e0b;
      --danger: #ef4444;
      --info: #3b82f6;
    }

    [data-theme="dark"] {
      --bg-color: #1a1a2e;
      --card-bg: #16213e;
      --text-primary: #eee;
      --text-secondary: #aaa;
      --border-color: #2d3748;
      --shadow-sm: 0 2px 8px rgba(0,0,0,0.3);
      --shadow-md: 0 10px 30px rgba(0,0,0,0.5);
      --shadow-lg: 0 20px 60px rgba(0,0,0,0.7);
    }

    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
      background: var(--bg-color);
      min-height: 100vh;
      padding: 20px;
      transition: background 0.3s ease;
    }

    body.gradient-bg {
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    }

    .container {
      max-width: 1400px;
      margin: 0 auto;
    }

    /* Header Styles */
    .header {
      background: var(--card-bg);
      padding: 30px;
      border-radius: 20px;
      box-shadow: var(--shadow-lg);
      margin-bottom: 30px;
      position: relative;
      overflow: hidden;
    }

    .header::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      height: 4px;
      background: var(--primary-gradient);
    }

    .header-top {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 20px;
      flex-wrap: wrap;
      gap: 15px;
    }

    .header h1 {
      font-size: 2.5em;
      color: var(--text-primary);
      margin: 0;
    }

    .header-actions {
      display: flex;
      gap: 10px;
      align-items: center;
    }

    .theme-toggle {
      background: var(--card-bg);
      border: 2px solid var(--border-color);
      color: var(--text-primary);
      width: 45px;
      height: 45px;
      border-radius: 50%;
      cursor: pointer;
      font-size: 20px;
      transition: all 0.3s ease;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .theme-toggle:hover {
      transform: rotate(180deg);
      border-color: #667eea;
    }

    .header p {
      color: var(--text-secondary);
      font-size: 1.1em;
      margin-bottom: 15px;
    }

    /* Search Bar */
    .search-container {
      position: relative;
      margin-top: 20px;
    }

    .search-input {
      width: 100%;
      padding: 15px 50px 15px 20px;
      border: 2px solid var(--border-color);
      border-radius: 12px;
      font-size: 16px;
      background: var(--card-bg);
      color: var(--text-primary);
      transition: all 0.3s ease;
    }

    .search-input:focus {
      outline: none;
      border-color: #667eea;
      box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
    }

    .search-icon {
      position: absolute;
      right: 20px;
      top: 50%;
      transform: translateY(-50%);
      color: var(--text-secondary);
      font-size: 18px;
    }

    /* Stats Grid */
    .stats-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
      gap: 20px;
      margin-bottom: 30px;
    }

    .stat-card {
      background: var(--card-bg);
      padding: 25px;
      border-radius: 15px;
      box-shadow: var(--shadow-md);
      text-align: center;
      transition: all 0.3s ease;
      position: relative;
      overflow: hidden;
    }

    .stat-card::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      height: 3px;
      background: var(--primary-gradient);
      transform: scaleX(0);
      transition: transform 0.3s ease;
    }

    .stat-card:hover::before {
      transform: scaleX(1);
    }

    .stat-card:hover {
      transform: translateY(-5px);
      box-shadow: var(--shadow-lg);
    }

    .stat-card .icon {
      font-size: 2.5em;
      margin-bottom: 10px;
      background: var(--primary-gradient);
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
    }

    .stat-card .number {
      font-size: 2.5em;
      font-weight: bold;
      color: var(--text-primary);
      margin-bottom: 10px;
      font-variant-numeric: tabular-nums;
    }

    .stat-card .label {
      color: var(--text-secondary);
      font-size: 0.95em;
      text-transform: uppercase;
      letter-spacing: 1px;
    }

    /* Loading Skeleton */
    .skeleton {
      background: linear-gradient(90deg, var(--border-color) 25%, rgba(102,126,234,0.1) 50%, var(--border-color) 75%);
      background-size: 200% 100%;
      animation: shimmer 1.5s infinite;
      border-radius: 8px;
    }

    .skeleton-text {
      height: 20px;
      margin-bottom: 10px;
    }

    .skeleton-title {
      height: 30px;
      width: 70%;
      margin-bottom: 15px;
    }

    @keyframes shimmer {
      0% { background-position: 200% 0; }
      100% { background-position: -200% 0; }
    }

    /* Tabs */
    .tabs {
      display: flex;
      gap: 10px;
      margin-bottom: 20px;
      flex-wrap: wrap;
    }

    .tab {
      background: var(--card-bg);
      padding: 15px 30px;
      border-radius: 10px;
      cursor: pointer;
      font-weight: 600;
      transition: all 0.3s ease;
      box-shadow: var(--shadow-sm);
      border: 2px solid transparent;
      color: var(--text-primary);
      text-decoration: none;
      display: inline-block;
    }

    .tab:hover {
      transform: translateY(-2px);
      box-shadow: var(--shadow-md);
      border-color: #667eea;
    }

    .tab.active {
      background: var(--primary-gradient);
      color: white;
    }

    .tab i {
      margin-right: 8px;
    }

    /* Content Panels */
    .content-panel {
      background: var(--card-bg);
      padding: 30px;
      border-radius: 20px;
      box-shadow: var(--shadow-lg);
      display: none;
      animation: fadeIn 0.3s ease;
    }

    .content-panel.active {
      display: block;
    }

    @keyframes fadeIn {
      from { opacity: 0; transform: translateY(10px); }
      to { opacity: 1; transform: translateY(0); }
    }

    /* Table Styles */
    .table-container {
      overflow-x: auto;
      max-height: 600px;
      overflow-y: auto;
      border-radius: 10px;
    }

    table {
      width: 100%;
      border-collapse: collapse;
    }

    th {
      background: var(--primary-gradient);
      color: white;
      padding: 15px;
      text-align: left;
      position: sticky;
      top: 0;
      z-index: 10;
      font-weight: 600;
      cursor: pointer;
      user-select: none;
    }

    th:hover {
      background: linear-gradient(135deg, #5568d3 0%, #653a8b 100%);
    }

    th i {
      margin-left: 5px;
      font-size: 0.8em;
    }

    td {
      padding: 12px 15px;
      border-bottom: 1px solid var(--border-color);
      color: var(--text-primary);
    }

    tr:hover {
      background: rgba(102, 126, 234, 0.05);
    }

    .favorite-btn {
      background: none;
      border: none;
      cursor: pointer;
      font-size: 18px;
      color: var(--text-secondary);
      transition: all 0.3s ease;
      padding: 5px;
    }

    .favorite-btn:hover {
      color: #f59e0b;
      transform: scale(1.2);
    }

    .favorite-btn.active {
      color: #f59e0b;
    }

    /* Brand List */
    .brand-list {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
      gap: 15px;
      margin-top: 20px;
    }

    .brand-item {
      background: rgba(102, 126, 234, 0.05);
      padding: 15px;
      border-radius: 10px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      transition: all 0.3s ease;
      border: 2px solid transparent;
    }

    .brand-item:hover {
      transform: translateY(-3px);
      border-color: #667eea;
      box-shadow: var(--shadow-sm);
    }

    .brand-name {
      font-weight: 600;
      color: var(--text-primary);
    }

    .brand-count {
      background: var(--primary-gradient);
      color: white;
      padding: 5px 12px;
      border-radius: 15px;
      font-size: 14px;
      font-weight: 600;
    }

    /* Charts */
    .chart-container {
      position: relative;
      height: 400px;
      margin-top: 30px;
      background: var(--card-bg);
      padding: 20px;
      border-radius: 15px;
      box-shadow: var(--shadow-sm);
    }

    /* Toast Notifications */
    .toast-container {
      position: fixed;
      top: 20px;
      right: 20px;
      z-index: 9999;
      max-width: 350px;
    }

    .toast {
      background: var(--card-bg);
      color: var(--text-primary);
      padding: 16px 20px;
      border-radius: 12px;
      box-shadow: var(--shadow-lg);
      margin-bottom: 10px;
      display: flex;
      align-items: center;
      gap: 12px;
      animation: slideIn 0.3s ease;
      border-left: 4px solid #667eea;
    }

    .toast.success { border-left-color: var(--success); }
    .toast.error { border-left-color: var(--danger); }
    .toast.warning { border-left-color: var(--warning); }
    .toast.info { border-left-color: var(--info); }

    @keyframes slideIn {
      from {
        transform: translateX(400px);
        opacity: 0;
      }
      to {
        transform: translateX(0);
        opacity: 1;
      }
    }

    .toast-icon {
      font-size: 20px;
    }

    .toast.success .toast-icon { color: var(--success); }
    .toast.error .toast-icon { color: var(--danger); }
    .toast.warning .toast-icon { color: var(--warning); }
    .toast.info .toast-icon { color: var(--info); }

    /* Buttons */
    .btn {
      background: var(--primary-gradient);
      color: white;
      padding: 12px 24px;
      border: none;
      border-radius: 10px;
      cursor: pointer;
      font-size: 16px;
      font-weight: 600;
      transition: all 0.3s ease;
      margin: 5px;
      display: inline-flex;
      align-items: center;
      gap: 8px;
    }

    .btn:hover {
      transform: translateY(-2px);
      box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
    }

    .btn:active {
      transform: translateY(0);
    }

    .btn-secondary {
      background: var(--card-bg);
      color: var(--text-primary);
      border: 2px solid var(--border-color);
    }

    /* Floating Action Buttons */
    .fab-container {
      position: fixed;
      bottom: 30px;
      right: 30px;
      display: flex;
      flex-direction: column;
      gap: 15px;
      z-index: 1000;
    }

    .fab {
      width: 60px;
      height: 60px;
      border-radius: 50%;
      background: var(--primary-gradient);
      color: white;
      border: none;
      font-size: 24px;
      cursor: pointer;
      box-shadow: var(--shadow-lg);
      transition: all 0.3s ease;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .fab:hover {
      transform: scale(1.1) rotate(90deg);
    }

    .fab-secondary {
      background: var(--card-bg);
      color: #667eea;
      width: 50px;
      height: 50px;
      font-size: 20px;
    }

    /* Status Badge */
    .status-badge {
      display: inline-block;
      padding: 5px 15px;
      border-radius: 20px;
      font-size: 12px;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.5px;
    }

    .status-success {
      background: var(--success);
      color: white;
    }

    .status-warning {
      background: var(--warning);
      color: white;
    }

    /* Empty State */
    .empty-state {
      text-align: center;
      padding: 60px 20px;
      color: var(--text-secondary);
    }

    .empty-state-icon {
      font-size: 80px;
      margin-bottom: 20px;
      opacity: 0.3;
    }

    .empty-state h3 {
      font-size: 1.8em;
      margin-bottom: 10px;
      color: var(--text-primary);
    }

    /* Comparison Feature */
    .compare-bar {
      position: fixed;
      bottom: 0;
      left: 0;
      right: 0;
      background: var(--card-bg);
      padding: 15px 20px;
      box-shadow: 0 -5px 20px rgba(0,0,0,0.2);
      transform: translateY(100%);
      transition: transform 0.3s ease;
      z-index: 999;
    }

    .compare-bar.active {
      transform: translateY(0);
    }

    .compare-content {
      max-width: 1400px;
      margin: 0 auto;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    .compare-items {
      display: flex;
      gap: 10px;
      flex: 1;
      overflow-x: auto;
    }

    .compare-item {
      background: rgba(102, 126, 234, 0.1);
      padding: 8px 15px;
      border-radius: 8px;
      display: flex;
      align-items: center;
      gap: 8px;
      white-space: nowrap;
    }

    .compare-item button {
      background: none;
      border: none;
      color: var(--danger);
      cursor: pointer;
      font-size: 16px;
    }

    /* Responsive Design */
    @media (max-width: 768px) {
      body {
        padding: 10px;
      }

      .header h1 {
        font-size: 1.8em;
      }

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

      .tabs {
        flex-direction: column;
      }

      .tab {
        width: 100%;
        text-align: center;
      }

      .fab-container {
        bottom: 20px;
        right: 20px;
      }

      .chart-container {
        height: 300px;
      }

      .header-actions {
        width: 100%;
        justify-content: flex-end;
      }
    }

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

    .loading {
      text-align: center;
      padding: 40px;
      color: var(--text-secondary);
    }

    .loading-spinner {
      display: inline-block;
      width: 40px;
      height: 40px;
      border: 4px solid var(--border-color);
      border-top-color: #667eea;
      border-radius: 50%;
      animation: spin 1s linear infinite;
    }

    @keyframes spin {
      to { transform: rotate(360deg); }
    }

    /* Log Container */
    .log-container {
      background: #1e1e1e;
      color: #00ff00;
      padding: 20px;
      border-radius: 10px;
      font-family: 'Courier New', monospace;
      max-height: 600px;
      overflow-y: auto;
      font-size: 14px;
      line-height: 1.6;
    }

    .log-line {
      margin-bottom: 5px;
      opacity: 0;
      animation: fadeInLog 0.3s ease forwards;
    }

    @keyframes fadeInLog {
      to { opacity: 1; }
    }
  </style>
</head>
<body class="gradient-bg">
  <!-- Toast Container -->
  <div class="toast-container" id="toastContainer"></div>

  <!-- Compare Bar -->
  <div class="compare-bar" id="compareBar">
    <div class="compare-content">
      <div class="compare-items" id="compareItems"></div>
      <div>
        <button class="btn" onclick="viewComparison()">
          <i class="fas fa-columns"></i> Compare
        </button>
        <button class="btn btn-secondary" onclick="clearComparison()">
          <i class="fas fa-times"></i> Clear
        </button>
      </div>
    </div>
  </div>

  <div class="container">
    <!-- Header -->
    <div class="header">
      <div class="header-top">
        <div>
          <h1><i class="fas fa-chart-line"></i> LUXVAULT</h1>
        </div>
        <div class="header-actions">
          <button class="theme-toggle" onclick="toggleTheme()" title="Toggle Theme">
            <i class="fas fa-moon" id="themeIcon"></i>
          </button>
        </div>
      </div>
      <p>Real-time monitoring of luxury handbag auction scraper</p>
      <div class="search-container">
        <input type="text" class="search-input" id="searchInput" placeholder="Search auctions by title, brand, or auction house..." onkeyup="searchAuctions()">
        <i class="fas fa-search search-icon"></i>
      </div>
      <div style="margin-top: 15px;">
        <span class="status-badge status-success" id="systemStatus">SYSTEM OPERATIONAL</span>
      </div>
    </div>

    <!-- Stats Grid -->
    <div class="stats-grid">
      <div class="stat-card">
        <div class="icon"><i class="fas fa-gavel"></i></div>
        <div class="number" id="totalAuctions">0</div>
        <div class="label">Total Auctions</div>
      </div>
      <div class="stat-card">
        <div class="icon"><i class="fas fa-tags"></i></div>
        <div class="number" id="brandsTracked">22</div>
        <div class="label">Brands Tracked</div>
      </div>
      <div class="stat-card">
        <div class="icon"><i class="fas fa-dollar-sign"></i></div>
        <div class="number" id="avgPrice">$0</div>
        <div class="label">Avg Price</div>
      </div>
      <div class="stat-card">
        <div class="icon"><i class="fas fa-database"></i></div>
        <div class="number" id="dbSize">0 KB</div>
        <div class="label">Database Size</div>
      </div>
      <div class="stat-card">
        <div class="icon"><i class="fas fa-star"></i></div>
        <div class="number" id="favoriteCount">0</div>
        <div class="label">Favorites</div>
      </div>
    </div>

    <!-- Tabs -->
    <div class="tabs">
      <div class="tab active" onclick="switchTab('auctions')">
        <i class="fas fa-table"></i> Auctions
      </div>
      <div class="tab" onclick="switchTab('stats')">
        <i class="fas fa-chart-bar"></i> Statistics
      </div>
      <div class="tab" onclick="switchTab('favorites')">
        <i class="fas fa-heart"></i> Favorites
      </div>
      <a href="/best-values.html" class="tab">
        <i class="fas fa-gem"></i> Best Values
      </a>
      <div class="tab" onclick="switchTab('logs')">
        <i class="fas fa-file-alt"></i> Logs
      </div>
      <div class="tab" onclick="switchTab('config')">
        <i class="fas fa-cog"></i> Configuration
      </div>
    </div>

    <!-- Auctions Panel -->
    <div id="auctions" class="content-panel active">
      <h2><i class="fas fa-gavel"></i> Auction Data</h2>
      <div class="table-container" id="auctionsTable">
        <div class="loading">
          <div class="loading-spinner"></div>
          <p>Loading auction data...</p>
        </div>
      </div>
    </div>

    <!-- Statistics Panel -->
    <div id="stats" class="content-panel">
      <h2><i class="fas fa-chart-bar"></i> Statistics & Analytics</h2>
      <div id="statsContent">
        <div class="loading">
          <div class="loading-spinner"></div>
          <p>Loading statistics...</p>
        </div>
      </div>
    </div>

    <!-- Favorites Panel -->
    <div id="favorites" class="content-panel">
      <h2><i class="fas fa-heart"></i> Favorite Auctions</h2>
      <div id="favoritesContent">
        <div class="empty-state">
          <div class="empty-state-icon"><i class="fas fa-heart"></i></div>
          <h3>No favorites yet</h3>
          <p>Click the star icon on any auction to add it to your favorites</p>
        </div>
      </div>
    </div>

    <!-- Logs Panel -->
    <div id="logs" class="content-panel">
      <h2><i class="fas fa-file-alt"></i> Scraper Logs</h2>
      <div style="margin-bottom: 20px;">
        <button class="btn" onclick="loadLogs()">
          <i class="fas fa-sync-alt"></i> Refresh Logs
        </button>
        <button class="btn" onclick="downloadCSV()">
          <i class="fas fa-download"></i> Download CSV
        </button>
      </div>
      <div class="log-container" id="logsContent">
        <div class="loading">Loading logs...</div>
      </div>
    </div>

    <!-- Configuration Panel -->
    <div id="config" class="content-panel">
      <h2><i class="fas fa-cog"></i> System Configuration</h2>
      <div id="configContent">
        <div class="loading">
          <div class="loading-spinner"></div>
          <p>Loading configuration...</p>
        </div>
      </div>
    </div>
  </div>

  <!-- Floating Action Buttons -->
  <div class="fab-container">
    <button class="fab fab-secondary" onclick="scrollToTop()" title="Scroll to Top">
      <i class="fas fa-arrow-up"></i>
    </button>
    <button class="fab" onclick="loadAllData()" title="Refresh All Data">
      <i class="fas fa-sync-alt"></i>
    </button>
  </div>

  <script>
    const API_BASE = window.location.origin;
    let allAuctions = [];
    let filteredAuctions = [];
    let favorites = JSON.parse(localStorage.getItem('luxvault_favorites') || '[]');
    let compareList = JSON.parse(localStorage.getItem('luxvault_compare') || '[]');

    // Theme Management
    function toggleTheme() {
      const html = document.documentElement;
      const currentTheme = html.getAttribute('data-theme');
      const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
      html.setAttribute('data-theme', newTheme);
      localStorage.setItem('luxvault_theme', newTheme);

      const icon = document.getElementById('themeIcon');
      icon.className = newTheme === 'dark' ? 'fas fa-sun' : 'fas fa-moon';

      showToast(newTheme === 'dark' ? 'Dark mode enabled' : 'Light mode enabled', 'success');
    }

    // Initialize theme
    const savedTheme = localStorage.getItem('luxvault_theme') || 'light';
    if (savedTheme === 'dark') {
      document.documentElement.setAttribute('data-theme', 'dark');
      document.getElementById('themeIcon').className = 'fas fa-sun';
    }

    // Toast Notifications
    function showToast(message, type = 'info', duration = 3000) {
      const container = document.getElementById('toastContainer');
      const toast = document.createElement('div');
      toast.className = `toast ${type}`;

      const icons = {
        success: 'fa-check-circle',
        error: 'fa-exclamation-circle',
        warning: 'fa-exclamation-triangle',
        info: 'fa-info-circle'
      };

      toast.innerHTML = `
        <i class="fas ${icons[type]} toast-icon"></i>
        <span>${message}</span>
      `;

      container.appendChild(toast);

      setTimeout(() => {
        toast.style.animation = 'slideIn 0.3s ease reverse';
        setTimeout(() => toast.remove(), 300);
      }, duration);
    }

    // Tab Switching
    function switchTab(tabName) {
      document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
      document.querySelectorAll('.content-panel').forEach(p => p.classList.remove('active'));
      event.target.classList.add('active');
      document.getElementById(tabName).classList.add('active');

      if (tabName === 'favorites') {
        loadFavorites();
      }
    }

    // Search Functionality
    function searchAuctions() {
      const query = document.getElementById('searchInput').value.toLowerCase();

      if (!query) {
        filteredAuctions = allAuctions;
      } else {
        filteredAuctions = allAuctions.filter(auction => {
          return (auction.title && auction.title.toLowerCase().includes(query)) ||
                 (auction.search_term && auction.search_term.toLowerCase().includes(query)) ||
                 (auction.auction_house && auction.auction_house.toLowerCase().includes(query));
        });
      }

      renderAuctionsTable(filteredAuctions);
    }

    // Favorites Management
    function toggleFavorite(auctionId) {
      const index = favorites.indexOf(auctionId);
      if (index > -1) {
        favorites.splice(index, 1);
        showToast('Removed from favorites', 'info');
      } else {
        favorites.push(auctionId);
        showToast('Added to favorites', 'success');
      }
      localStorage.setItem('luxvault_favorites', JSON.stringify(favorites));
      updateFavoriteCount();

      // Update button state
      const btn = document.querySelector(`[data-auction-id="${auctionId}"]`);
      if (btn) {
        btn.classList.toggle('active');
      }
    }

    function updateFavoriteCount() {
      document.getElementById('favoriteCount').textContent = favorites.length;
    }

    function loadFavorites() {
      const favoriteAuctions = allAuctions.filter(a => favorites.includes(a.id));

      if (favoriteAuctions.length === 0) {
        document.getElementById('favoritesContent').innerHTML = `
          <div class="empty-state">
            <div class="empty-state-icon"><i class="fas fa-heart"></i></div>
            <h3>No favorites yet</h3>
            <p>Click the star icon on any auction to add it to your favorites</p>
          </div>
        `;
        return;
      }

      renderAuctionsTable(favoriteAuctions, 'favoritesContent');
    }

    // Comparison Feature
    function addToCompare(auctionId) {
      if (compareList.includes(auctionId)) {
        showToast('Already in comparison list', 'warning');
        return;
      }

      if (compareList.length >= 4) {
        showToast('Maximum 4 items can be compared', 'warning');
        return;
      }

      compareList.push(auctionId);
      localStorage.setItem('luxvault_compare', JSON.stringify(compareList));
      updateCompareBar();
      showToast('Added to comparison', 'success');
    }

    function removeFromCompare(auctionId) {
      compareList = compareList.filter(id => id !== auctionId);
      localStorage.setItem('luxvault_compare', JSON.stringify(compareList));
      updateCompareBar();
    }

    function updateCompareBar() {
      const bar = document.getElementById('compareBar');
      const items = document.getElementById('compareItems');

      if (compareList.length === 0) {
        bar.classList.remove('active');
        return;
      }

      bar.classList.add('active');
      items.innerHTML = compareList.map(id => {
        const auction = allAuctions.find(a => a.id === id);
        if (!auction) return '';
        return `
          <div class="compare-item">
            <span>${auction.title ? auction.title.substring(0, 50) : 'Auction #' + id}</span>
            <button onclick="removeFromCompare(${id})"><i class="fas fa-times"></i></button>
          </div>
        `;
      }).join('');
    }

    function clearComparison() {
      compareList = [];
      localStorage.setItem('luxvault_compare', JSON.stringify([]));
      updateCompareBar();
      showToast('Comparison cleared', 'info');
    }

    function viewComparison() {
      if (compareList.length < 2) {
        showToast('Add at least 2 items to compare', 'warning');
        return;
      }

      const compareAuctions = allAuctions.filter(a => compareList.includes(a.id));

      let html = '<div style="overflow-x: auto;"><table><thead><tr><th>Property</th>';
      compareAuctions.forEach((a, i) => {
        html += `<th>Item ${i + 1}</th>`;
      });
      html += '</tr></thead><tbody>';

      const fields = [
        ['Title', 'title'],
        ['Brand', 'search_term'],
        ['Current Price', 'current_price'],
        ['Estimate Low', 'estimate_low'],
        ['Estimate High', 'estimate_high'],
        ['Auction House', 'auction_house'],
        ['End Date', 'end_date']
      ];

      fields.forEach(([label, field]) => {
        html += `<tr><td><strong>${label}</strong></td>`;
        compareAuctions.forEach(a => {
          let value = a[field] || 'N/A';
          if (field.includes('price') && value !== 'N/A') {
            value = '$' + value.toLocaleString();
          }
          html += `<td>${value}</td>`;
        });
        html += '</tr>';
      });

      html += '</tbody></table></div>';

      const panel = document.getElementById('auctionsTable');
      panel.innerHTML = html;
      switchTab('auctions');
      showToast('Viewing comparison', 'info');
    }

    // Load Auctions
    async function loadAuctions() {
      try {
        const res = await fetch(`${API_BASE}/api/auctions`);
        const data = await res.json();

        allAuctions = data.data || [];
        filteredAuctions = allAuctions;

        document.getElementById('totalAuctions').textContent = data.count;

        if (data.count === 0) {
          document.getElementById('auctionsTable').innerHTML = `
            <div class="empty-state">
              <div class="empty-state-icon"><i class="fas fa-gavel"></i></div>
              <h3>No auction data yet</h3>
              <p>The scraper will run daily at 6:00 AM and populate this table.</p>
              <p style="margin-top: 20px;">Database is initialized and ready to receive data.</p>
            </div>
          `;
          return;
        }

        renderAuctionsTable(filteredAuctions);
        updateFavoriteCount();
        updateCompareBar();
      } catch (error) {
        document.getElementById('auctionsTable').innerHTML = `
          <div class="empty-state">
            <div class="empty-state-icon"><i class="fas fa-exclamation-circle"></i></div>
            <h3>Error loading data</h3>
            <p>${error.message}</p>
          </div>
        `;
        showToast('Failed to load auctions', 'error');
      }
    }

    function renderAuctionsTable(auctions, containerId = 'auctionsTable') {
      let html = `
        <table>
          <thead>
            <tr>
              <th><i class="fas fa-star"></i></th>
              <th>ID</th>
              <th>Title</th>
              <th>Auction House</th>
              <th>Price <i class="fas fa-sort"></i></th>
              <th>Estimate</th>
              <th>End Date</th>
              <th>Brand</th>
              <th>Actions</th>
            </tr>
          </thead>
          <tbody>
      `;

      auctions.forEach(auction => {
        const isFavorite = favorites.includes(auction.id);
        html += `
          <tr>
            <td>
              <button class="favorite-btn ${isFavorite ? 'active' : ''}"
                      data-auction-id="${auction.id}"
                      onclick="toggleFavorite(${auction.id})">
                <i class="fas fa-star"></i>
              </button>
            </td>
            <td>${auction.id}</td>
            <td><a href="${auction.url}" target="_blank" style="color: #667eea; text-decoration: none; font-weight: 600;">${auction.title || 'N/A'}</a></td>
            <td>${auction.auction_house || 'N/A'}</td>
            <td style="font-weight: 600; color: #10b981;">${auction.current_price ? '$' + auction.current_price.toLocaleString() : 'N/A'}</td>
            <td>${auction.estimate_low && auction.estimate_high ? '$' + auction.estimate_low.toLocaleString() + ' - $' + auction.estimate_high.toLocaleString() : 'N/A'}</td>
            <td>${auction.end_date || 'N/A'}</td>
            <td><span class="status-badge" style="background: rgba(102,126,234,0.2); color: #667eea;">${auction.search_term}</span></td>
            <td>
              <button class="btn btn-secondary" style="padding: 6px 12px; margin: 0;" onclick="addToCompare(${auction.id})">
                <i class="fas fa-plus"></i> Compare
              </button>
            </td>
          </tr>
        `;
      });

      html += '</tbody></table>';
      document.getElementById(containerId).innerHTML = html;
    }

    // Load Statistics
    async function loadStats() {
      try {
        const res = await fetch(`${API_BASE}/api/stats`);
        const data = await res.json();

        if (data.success) {
          const stats = data.stats;

          document.getElementById('avgPrice').textContent = stats.avgPrice > 0
            ? '$' + Math.round(stats.avgPrice).toLocaleString()
            : '$0';

          let html = `
            <h3><i class="fas fa-tags"></i> Auctions by Brand</h3>
            <div class="brand-list">
          `;

          if (stats.byBrand.length > 0) {
            stats.byBrand.forEach(brand => {
              html += `
                <div class="brand-item">
                  <span class="brand-name">${brand.search_term}</span>
                  <span class="brand-count">${brand.count}</span>
                </div>
              `;
            });
          } else {
            html += '<p style="padding: 20px;">No data yet - waiting for first scrape run</p>';
          }

          html += '</div>';

          // Add chart
          html += '<div class="chart-container"><canvas id="priceChart"></canvas></div>';

          if (stats.byAuctionHouse.length > 0) {
            html += '<h3 style="margin-top: 30px;"><i class="fas fa-building"></i> Auctions by House</h3><div class="brand-list">';
            stats.byAuctionHouse.forEach(house => {
              html += `
                <div class="brand-item">
                  <span class="brand-name">${house.auction_house}</span>
                  <span class="brand-count">${house.count}</span>
                </div>
              `;
            });
            html += '</div>';
          }

          if (stats.priceRange.min_price > 0) {
            html += `
              <h3 style="margin-top: 30px;"><i class="fas fa-dollar-sign"></i> Price Range</h3>
              <div class="brand-list">
                <div class="brand-item">
                  <span class="brand-name">Minimum Price</span>
                  <span class="brand-count">$${stats.priceRange.min_price.toLocaleString()}</span>
                </div>
                <div class="brand-item">
                  <span class="brand-name">Maximum Price</span>
                  <span class="brand-count">$${stats.priceRange.max_price.toLocaleString()}</span>
                </div>
              </div>
            `;
          }

          document.getElementById('statsContent').innerHTML = html;

          // Render chart if we have data
          if (stats.byBrand.length > 0) {
            setTimeout(() => renderChart(stats.byBrand), 100);
          }
        }
      } catch (error) {
        document.getElementById('statsContent').innerHTML = `
          <div class="empty-state">
            <div class="empty-state-icon"><i class="fas fa-exclamation-circle"></i></div>
            <h3>Error loading statistics</h3>
            <p>${error.message}</p>
          </div>
        `;
        showToast('Failed to load statistics', 'error');
      }
    }

    // Render Chart
    function renderChart(brandData) {
      const ctx = document.getElementById('priceChart');
      if (!ctx) return;

      new Chart(ctx, {
        type: 'bar',
        data: {
          labels: brandData.slice(0, 10).map(b => b.search_term),
          datasets: [{
            label: 'Number of Auctions',
            data: brandData.slice(0, 10).map(b => b.count),
            backgroundColor: 'rgba(102, 126, 234, 0.6)',
            borderColor: '#667eea',
            borderWidth: 2
          }]
        },
        options: {
          responsive: true,
          maintainAspectRatio: false,
          plugins: {
            legend: {
              display: false
            },
            title: {
              display: true,
              text: 'Top 10 Brands by Auction Count'
            }
          },
          scales: {
            y: {
              beginAtZero: true,
              ticks: {
                precision: 0
              }
            }
          }
        }
      });
    }

    // Load Logs
    async function loadLogs() {
      try {
        const res = await fetch(`${API_BASE}/api/logs`);
        const data = await res.json();

        if (data.success) {
          const html = data.logs.map((line, i) =>
            `<div class="log-line" style="animation-delay: ${i * 0.01}s">${line}</div>`
          ).join('');
          document.getElementById('logsContent').innerHTML = html || '<div class="empty-state">No logs yet</div>';
          showToast('Logs refreshed', 'success');
        }
      } catch (error) {
        document.getElementById('logsContent').innerHTML = `<div class="empty-state">Error: ${error.message}</div>`;
        showToast('Failed to load logs', 'error');
      }
    }

    // Load Configuration
    async function loadConfig() {
      const config = {
        'Scraper Script': '/root/Projects/handbag-auth-nextjs/scripts/scrape-auction-data.py',
        'Database': '/root/Projects/handbag-auth-nextjs/data/auction-history/auctions.db',
        'CSV Export': '/root/Projects/handbag-auth-nextjs/data/auction-history/auction-history.csv',
        'Logs': '/root/Projects/handbag-auth-nextjs/data/auction-history/scraper.log',
        'Cron Schedule': '0 6 * * * (Daily at 6:00 AM)',
        'Brands Monitored': '22 luxury handbag models',
        'Rate Limit': '2 seconds between requests',
        'Python Version': '3.10',
        'Dependencies': 'BeautifulSoup4, requests, lxml, sqlite3'
      };

      try {
        const res = await fetch(`${API_BASE}/api/status`);
        const data = await res.json();

        if (data.success) {
          document.getElementById('dbSize').textContent = (data.status.dbSize / 1024).toFixed(2) + ' KB';
        }

        let html = '<h3><i class="fas fa-cog"></i> Configuration</h3><div class="brand-list">';
        Object.keys(config).forEach(key => {
          html += `
            <div class="brand-item" style="grid-column: span 2;">
              <span class="brand-name">${key}</span>
              <span style="color: var(--text-secondary); font-size: 0.9em;">${config[key]}</span>
            </div>
          `;
        });
        html += '</div>';

        html += `
          <h3 style="margin-top: 30px;"><i class="fas fa-info-circle"></i> System Status</h3>
          <div class="brand-list">
            <div class="brand-item">
              <span class="brand-name">Database File</span>
              <span class="status-badge ${data.status.database ? 'status-success' : 'status-warning'}">${data.status.database ? 'EXISTS' : 'MISSING'}</span>
            </div>
            <div class="brand-item">
              <span class="brand-name">CSV File</span>
              <span class="status-badge ${data.status.csv ? 'status-success' : 'status-warning'}">${data.status.csv ? 'EXISTS' : 'MISSING'}</span>
            </div>
            <div class="brand-item">
              <span class="brand-name">Log File</span>
              <span class="status-badge ${data.status.logs ? 'status-success' : 'status-warning'}">${data.status.logs ? 'EXISTS' : 'MISSING'}</span>
            </div>
            <div class="brand-item">
              <span class="brand-name">DB Size</span>
              <span class="brand-count">${(data.status.dbSize / 1024).toFixed(2)} KB</span>
            </div>
            <div class="brand-item">
              <span class="brand-name">CSV Size</span>
              <span class="brand-count">${(data.status.csvSize / 1024).toFixed(2)} KB</span>
            </div>
            <div class="brand-item">
              <span class="brand-name">Log Size</span>
              <span class="brand-count">${(data.status.logSize / 1024).toFixed(2)} KB</span>
            </div>
          </div>
        `;

        document.getElementById('configContent').innerHTML = html;
      } catch (error) {
        document.getElementById('configContent').innerHTML = `
          <div class="empty-state">
            <div class="empty-state-icon"><i class="fas fa-exclamation-circle"></i></div>
            <h3>Error loading configuration</h3>
            <p>${error.message}</p>
          </div>
        `;
      }
    }

    // Download CSV
    function downloadCSV() {
      window.open(`${API_BASE}/api/download-csv`, '_blank');
      showToast('Downloading CSV...', 'info');
    }

    // Scroll to Top
    function scrollToTop() {
      window.scrollTo({ top: 0, behavior: 'smooth' });
    }

    // Load All Data
    async function loadAllData() {
      showToast('Refreshing data...', 'info');
      await Promise.all([
        loadAuctions(),
        loadStats(),
        loadLogs(),
        loadConfig()
      ]);
      showToast('Data refreshed successfully', 'success');
    }

    // Initialize
    loadAllData();
    setInterval(loadAllData, 60000); // Auto-refresh every 60 seconds
  </script>
</body>
</html>