// PEER Audit Dashboard - Bootstrap Sidebar Version

// State
let currentProject = null;
let currentScan = null;
let scanHistory = [];
let currentSection = 'overview';
let trendChart = null;
let drillData = {}; // Cache for drill-down data

// DOM ready
document.addEventListener('DOMContentLoaded', async () => {
  console.log('PEER Audit Dashboard initializing...');

  try {
    await loadProjects();
    setupNavigation();
    console.log('Dashboard ready');
  } catch (error) {
    console.error('Init failed:', error);
    showToast('Error', 'Failed to initialize dashboard: ' + error.message, 'danger');
  }
});

// ============================================
// NAVIGATION
// ============================================

function setupNavigation() {
  // Sidebar navigation clicks
  document.querySelectorAll('.sidebar-nav .nav-link').forEach(link => {
    link.addEventListener('click', (e) => {
      e.preventDefault();
      const section = link.dataset.section;
      if (section) {
        navigateToSection(section);
      }
    });
  });
}

function navigateToSection(section) {
  // Update nav active state
  document.querySelectorAll('.sidebar-nav .nav-link').forEach(link => {
    link.classList.toggle('active', link.dataset.section === section);
  });

  // Hide all sections
  document.querySelectorAll('.content-section').forEach(sec => {
    sec.classList.add('d-none');
  });

  // Show target section
  const targetSection = document.getElementById(`section-${section}`);
  if (targetSection) {
    targetSection.classList.remove('d-none');
  }

  // Hide loading state
  document.getElementById('loading-state').classList.add('d-none');

  currentSection = section;
}

// ============================================
// PROJECTS
// ============================================

async function loadProjects() {
  try {
    const res = await fetch('/api/projects');
    const data = await res.json();

    const selector = document.getElementById('project-selector');
    selector.innerHTML = '<option value="">Select project...</option>';

    if (data.success && data.projects.length > 0) {
      data.projects.forEach(project => {
        const option = document.createElement('option');
        option.value = project.project_path;
        option.textContent = project.name || project.project_path.split('/').pop();
        selector.appendChild(option);
      });

      // Auto-select first project
      if (data.projects.length > 0) {
        selector.value = data.projects[0].project_path;
        await selectProject(data.projects[0].project_path);
      }
    }

    selector.addEventListener('change', (e) => {
      if (e.target.value) {
        selectProject(e.target.value);
      }
    });
  } catch (error) {
    console.error('Failed to load projects:', error);
  }
}

async function selectProject(projectPath) {
  currentProject = projectPath;
  document.getElementById('project-name').textContent = projectPath;

  // Load latest scan
  try {
    const res = await fetch(`/api/scans/latest/${encodeURIComponent(projectPath)}?includeRaw=1`);
    const data = await res.json();

    if (data.success && data.scan) {
      currentScan = data.scan;
      await loadScanData();
      navigateToSection('overview');
    } else {
      showToast('Info', 'No scans found. Click Rescan to analyze this project.', 'info');
    }
  } catch (error) {
    console.error('Failed to load scan:', error);
    showToast('Error', 'Failed to load scan data', 'danger');
  }
}

// ============================================
// DATA LOADING
// ============================================

async function loadScanData() {
  if (!currentScan) return;

  const scan = currentScan;
  const raw = scan.raw_data ? JSON.parse(scan.raw_data) : {};

  // Clear drill data cache when loading new scan
  drillData = {};

  // Update last scan time
  document.getElementById('last-scan-time').textContent =
    `Last scan: ${formatDate(scan.created_at)}`;

  // Load all sections - pass full raw data
  updateOverview(raw);
  updateWaste(raw);
  updateSecurity(raw);
  updateDependencies(raw);
  updateEmissions(raw);
  await loadFixModules();
  await loadQuarantine();
  await loadScanHistory();
  await loadQuickFixes();
}

// ============================================
// OVERVIEW SECTION
// ============================================

function updateOverview(raw) {
  const summary = raw.summary || {};
  const healthScore = raw.healthScore || {};
  const security = raw.security || {};
  const outdated = raw.outdated || [];
  const emissions = raw.emissions || {};

  // Get score from healthScore object
  const score = healthScore.score || 0;
  const grade = healthScore.grade || getGrade(score);

  document.getElementById('health-score').textContent = score;
  document.getElementById('health-grade').textContent = grade;
  document.getElementById('health-summary').textContent = getScoreDescription(score);

  // Score circle color
  const circle = document.getElementById('health-score-circle');
  circle.className = 'score-circle score-' + grade.toLowerCase();

  // Calculate component scores from actual data
  const wasteScore = calculateWasteScore(raw);
  const securityScore = calculateSecurityScore(raw);
  const depsScore = calculateDepsScore(raw);
  const emissionsScore = calculateEmissionsScore(raw);

  // Score breakdown bars
  document.getElementById('score-waste').textContent = `${wasteScore}/30`;
  document.getElementById('score-waste-bar').style.width = `${(wasteScore / 30) * 100}%`;

  document.getElementById('score-security').textContent = `${securityScore}/40`;
  document.getElementById('score-security-bar').style.width = `${(securityScore / 40) * 100}%`;

  document.getElementById('score-deps').textContent = `${depsScore}/20`;
  document.getElementById('score-deps-bar').style.width = `${(depsScore / 20) * 100}%`;

  document.getElementById('score-emissions').textContent = `${emissionsScore}/10`;
  document.getElementById('score-emissions-bar').style.width = `${(emissionsScore / 10) * 100}%`;

  // Quick stats
  const wastePercent = summary.wastePercent || 0;
  document.getElementById('stat-waste').textContent = `${wastePercent.toFixed(1)}%`;

  const securityIssues = (security.vulnerabilities || []).length;
  document.getElementById('stat-security').textContent = securityIssues;

  const outdatedCount = outdated.length;
  document.getElementById('stat-outdated').textContent = outdatedCount;

  const co2 = emissions.current?.monthlyCO2Kg || 0;
  document.getElementById('stat-co2').textContent = `${co2.toFixed(2)} kg`;

  // Update nav badges
  updateNavBadge('nav-badge-waste', wastePercent > 5 ? `${wastePercent.toFixed(0)}%` : '');
  updateNavBadge('nav-badge-security', securityIssues > 0 ? securityIssues : '');
  updateNavBadge('nav-badge-deps', outdatedCount > 0 ? outdatedCount : '');
}

function updateNavBadge(id, value) {
  const badge = document.getElementById(id);
  if (badge) {
    badge.textContent = value;
    badge.style.display = value ? 'inline-block' : 'none';
  }
}

// ============================================
// WASTE SECTION
// ============================================

function updateWaste(raw) {
  const summary = raw.summary || {};
  const details = raw.details || {};
  const deadCode = details.deadCode || {};

  // Summary
  const wastePercent = summary.wastePercent || 0;
  document.getElementById('waste-total-percent').textContent = `${wastePercent.toFixed(1)}%`;
  document.getElementById('waste-total-size').textContent =
    `${formatBytes(summary.wasteSizeBytes || 0)} of codebase`;

  // Counts - unusedDeps is in details.unusedDeps
  const unusedDeps = details.unusedDeps || [];
  const orphanFiles = deadCode.fullyDeadFiles || deadCode.orphanFiles || [];
  const unusedAssets = details.unusedAssets || [];

  document.getElementById('waste-unused-deps-count').textContent = unusedDeps.length;
  document.getElementById('waste-dead-code-count').textContent = orphanFiles.length;
  document.getElementById('waste-assets-count').textContent = unusedAssets.length;

  // Unused dependencies table with expandable rows
  const unusedDepsList = document.getElementById('unused-deps-list');
  document.getElementById('unused-deps-badge').textContent = unusedDeps.length;

  if (unusedDeps.length === 0) {
    unusedDepsList.innerHTML = `
      <tr><td colspan="6" class="text-center text-muted py-4">
        <i class="bi bi-check-circle text-success"></i> No unused dependencies
      </td></tr>`;
  } else {
    unusedDepsList.innerHTML = unusedDeps.map((dep, i) => {
      const rowId = `unused-dep-${i}`;
      const expandedContent = renderUnusedDepExpanded(dep);

      return `
        <tr class="expandable-row" data-row-id="${rowId}" data-row-type="unused-dep" data-item-id="${escapeHtml(dep.name)}">
          <td class="expand-toggle" onclick="toggleRowExpand('${rowId}')">
            <i class="bi bi-chevron-right"></i>
          </td>
          <td><code>${escapeHtml(dep.name)}</code></td>
          <td>${escapeHtml(dep.version || '-')}</td>
          <td>${formatBytes(dep.sizeBytes || 50000)}</td>
          <td>${ConfidenceBadge(dep.confidence || 'high')}</td>
          <td>
            <div class="command-block small">
              <code>npm uninstall ${escapeHtml(dep.name)}</code>
              <button class="btn btn-sm btn-outline-secondary btn-copy"
                      onclick="event.stopPropagation(); copyCommand('npm uninstall ${escapeHtml(dep.name)}')">
                <i class="bi bi-clipboard"></i>
              </button>
            </div>
          </td>
        </tr>
        <tr class="expanded-content-row d-none" data-expanded-for="${rowId}">
          <td colspan="6">
            <div class="expanded-content">
              ${expandedContent}
            </div>
          </td>
        </tr>
      `;
    }).join('');
  }

  // Dead code table with expandable rows
  const deadCodeList = document.getElementById('dead-code-list');
  document.getElementById('dead-code-badge').textContent = orphanFiles.length;

  if (orphanFiles.length === 0) {
    deadCodeList.innerHTML = `
      <tr><td colspan="5" class="text-center text-muted py-4">
        <i class="bi bi-check-circle text-success"></i> No orphan files detected
      </td></tr>`;
  } else {
    deadCodeList.innerHTML = orphanFiles.slice(0, 30).map((file, i) => {
      const rowId = `dead-code-${i}`;
      const expandedContent = renderDeadCodeExpanded(file);

      return `
        <tr class="expandable-row" data-row-id="${rowId}" data-row-type="dead-code" data-item-id="${escapeHtml(file.relativePath || file.file)}">
          <td class="expand-toggle" onclick="toggleRowExpand('${rowId}')">
            <i class="bi bi-chevron-right"></i>
          </td>
          <td><code>${escapeHtml(file.relativePath || file.file)}</code></td>
          <td>${file.deadExports?.length || file.exports?.length || 0}</td>
          <td>${formatBytes(file.sizeBytes || 0)}</td>
          <td>${ConfidenceBadge(file.confidence || 'high')}</td>
        </tr>
        <tr class="expanded-content-row d-none" data-expanded-for="${rowId}">
          <td colspan="5">
            <div class="expanded-content">
              ${expandedContent}
            </div>
          </td>
        </tr>
      `;
    }).join('');
  }

  // Unused assets table (if container exists)
  const unusedAssetsList = document.getElementById('unused-assets-list');
  if (unusedAssetsList) {
    const assetsCountBadge = document.getElementById('unused-assets-badge');
    if (assetsCountBadge) assetsCountBadge.textContent = unusedAssets.length;

    if (unusedAssets.length === 0) {
      unusedAssetsList.innerHTML = `
        <tr><td colspan="5" class="text-center text-muted py-4">
          <i class="bi bi-check-circle text-success"></i> No unused assets detected
        </td></tr>`;
    } else {
      unusedAssetsList.innerHTML = unusedAssets.slice(0, 30).map((asset, i) => {
        const rowId = `unused-asset-${i}`;
        const expandedContent = renderAssetExpanded(asset);

        return `
          <tr class="expandable-row" data-row-id="${rowId}" data-row-type="asset" data-item-id="${escapeHtml(asset.relativePath || asset.path)}">
            <td class="expand-toggle" onclick="toggleRowExpand('${rowId}')">
              <i class="bi bi-chevron-right"></i>
            </td>
            <td><code>${escapeHtml((asset.relativePath || asset.path).split('/').pop())}</code></td>
            <td>${escapeHtml(asset.type || asset.format || '-')}</td>
            <td>${formatBytes(asset.sizeBytes || 0)}</td>
            <td>${ConfidenceBadge(asset.confidence || 'medium')}</td>
          </tr>
          <tr class="expanded-content-row d-none" data-expanded-for="${rowId}">
            <td colspan="5">
              <div class="expanded-content">
                ${expandedContent}
              </div>
            </td>
          </tr>
        `;
      }).join('');
    }
  }
}

// ============================================
// SECURITY SECTION
// ============================================

function updateSecurity(raw) {
  const security = raw.security || {};
  const vulnerabilities = security.vulnerabilities || [];

  // Count by severity
  const counts = { critical: 0, high: 0, medium: 0, low: 0 };
  vulnerabilities.forEach(v => {
    const sev = (v.severity || 'low').toLowerCase();
    if (counts[sev] !== undefined) counts[sev]++;
  });

  document.getElementById('security-critical').textContent = counts.critical;
  document.getElementById('security-high').textContent = counts.high;
  document.getElementById('security-medium').textContent = counts.medium;
  document.getElementById('security-low').textContent = counts.low;

  // Vulnerabilities table with expandable rows
  const vulnTable = document.getElementById('vulnerabilities-list');

  if (vulnerabilities.length === 0) {
    vulnTable.innerHTML = `
      <div class="text-center text-muted py-4">
        <i class="bi bi-shield-check text-success display-6"></i>
        <p class="mt-2 mb-0">No vulnerabilities detected</p>
      </div>`;
  } else {
    // Create table structure
    vulnTable.innerHTML = `
      <table class="table table-hover mb-0">
        <thead>
          <tr>
            <th style="width: 40px"></th>
            <th>Severity</th>
            <th>Package</th>
            <th>Version</th>
            <th>Title</th>
            <th>Actual Risk</th>
            <th>Fix</th>
          </tr>
        </thead>
        <tbody id="vuln-table-body"></tbody>
      </table>
    `;

    const tbody = document.getElementById('vuln-table-body');
    tbody.innerHTML = vulnerabilities.map((v, i) => {
      const rowId = `vuln-${i}`;
      const severity = (v.severity || 'unknown').toLowerCase();
      const usage = v.usage || v.usageAnalysis || {};
      const actualRisk = usage.actualRisk || severity;

      // Determine actual risk badge
      let riskBadge = '';
      if (usage.isUsed === false) {
        riskBadge = `<span class="status-badge status-unused">Not Used</span>`;
      } else if (actualRisk !== severity) {
        riskBadge = SeverityBadge(actualRisk);
      } else {
        riskBadge = `<span class="text-muted">-</span>`;
      }

      // Build expanded content
      const expandedContent = renderVulnerabilityExpanded(v);

      return `
        <tr class="expandable-row" data-row-id="${rowId}" data-row-type="vulnerability" data-item-id="${escapeHtml(v.package || v.name)}">
          <td class="expand-toggle" onclick="toggleRowExpand('${rowId}')">
            <i class="bi bi-chevron-right"></i>
          </td>
          <td>${SeverityBadge(severity)}</td>
          <td><code>${escapeHtml(v.package || v.name)}</code></td>
          <td>${escapeHtml(v.version || '-')}</td>
          <td class="text-truncate" style="max-width: 200px" title="${escapeHtml(v.title || v.description || '')}">${escapeHtml(v.title || v.description || 'No description')}</td>
          <td>${riskBadge}</td>
          <td>${v.fixedIn ? `<span class="text-success">${escapeHtml(v.fixedIn)}</span>` : '<span class="text-muted">-</span>'}</td>
        </tr>
        <tr class="expanded-content-row d-none" data-expanded-for="${rowId}">
          <td colspan="7">
            <div class="expanded-content">
              ${expandedContent}
            </div>
          </td>
        </tr>
      `;
    }).join('');
  }
}

// ============================================
// DEPENDENCIES SECTION
// ============================================

function updateDependencies(raw) {
  const summary = raw.summary || {};
  const details = raw.details || {};
  const outdatedPkgs = raw.outdated || [];  // Array at top level
  const licenses = raw.licenses || {};

  // Total dependency count
  const totalDeps = summary.dependencyCount || (details.dependencies?.all?.length) || 0;
  document.getElementById('deps-total').textContent = totalDeps;

  // Count by update type
  let major = 0, minor = 0, patch = 0;
  outdatedPkgs.forEach(pkg => {
    const type = pkg.updateType || 'patch';
    if (type === 'major') major++;
    else if (type === 'minor') minor++;
    else patch++;
  });

  document.getElementById('deps-major').textContent = major;
  document.getElementById('deps-minor').textContent = minor;
  document.getElementById('deps-patch').textContent = patch;

  // Outdated table with expandable rows
  const outdatedContainer = document.getElementById('outdated-deps-list');

  if (outdatedPkgs.length === 0) {
    outdatedContainer.innerHTML = `
      <tr><td colspan="7" class="text-center text-muted py-4">
        <i class="bi bi-check-circle text-success"></i> All dependencies up to date
      </td></tr>`;
  } else {
    outdatedContainer.innerHTML = outdatedPkgs.map((pkg, i) => {
      const rowId = `outdated-${i}`;
      const updateType = pkg.updateType || 'patch';
      const health = pkg.health || {};

      // Health indicator
      let healthBadge = '';
      if (health.deprecated) {
        healthBadge = `<span class="status-badge status-deprecated">Deprecated</span>`;
      } else if (!health.maintained) {
        healthBadge = `<span class="status-badge" style="background: rgba(248, 81, 73, 0.2); color: var(--accent-red);">Unmaintained</span>`;
      } else {
        healthBadge = `<span class="text-muted">-</span>`;
      }

      // Security fixes indicator
      const securityFixes = pkg.securityFixes?.length || 0;
      const securityBadge = securityFixes > 0
        ? `<span class="badge bg-danger">${securityFixes} fix${securityFixes > 1 ? 'es' : ''}</span>`
        : '<span class="text-muted">-</span>';

      // Build expanded content
      const expandedContent = renderOutdatedExpanded(pkg);

      return `
        <tr class="expandable-row" data-row-id="${rowId}" data-row-type="outdated" data-item-id="${escapeHtml(pkg.name)}">
          <td class="expand-toggle" onclick="toggleRowExpand('${rowId}')">
            <i class="bi bi-chevron-right"></i>
          </td>
          <td><code>${escapeHtml(pkg.name)}</code></td>
          <td>${escapeHtml(pkg.current || pkg.version)}</td>
          <td>${escapeHtml(pkg.latest)}</td>
          <td><span class="update-type ${updateType}">${updateType}</span></td>
          <td>${healthBadge}</td>
          <td>${securityBadge}</td>
        </tr>
        <tr class="expanded-content-row d-none" data-expanded-for="${rowId}">
          <td colspan="7">
            <div class="expanded-content">
              ${expandedContent}
            </div>
          </td>
        </tr>
      `;
    }).join('');
  }

  // Licenses table
  const licenseList = document.getElementById('licenses-list');
  const licenseGroups = licenses.byLicense || {};
  const licenseEntries = Object.entries(licenseGroups);

  document.getElementById('licenses-badge').textContent = `${totalDeps} packages`;

  if (licenseEntries.length === 0) {
    licenseList.innerHTML = `
      <tr><td colspan="3" class="text-center text-muted py-4">No license data available</td></tr>`;
  } else {
    licenseList.innerHTML = licenseEntries.map(([license, packages]) => {
      const risk = getLicenseRisk(license);
      return `
        <tr>
          <td>${escapeHtml(license)}</td>
          <td>${packages.length}</td>
          <td><span class="license-risk ${risk}">${risk}</span></td>
        </tr>
      `;
    }).join('');
  }
}

function getLicenseRisk(license) {
  const highRisk = ['GPL', 'AGPL', 'LGPL', 'SSPL'];
  const mediumRisk = ['MPL', 'EPL', 'CDDL'];

  const upper = (license || '').toUpperCase();
  if (highRisk.some(l => upper.includes(l))) return 'high';
  if (mediumRisk.some(l => upper.includes(l))) return 'medium';
  return 'low';
}

// ============================================
// EMISSIONS SECTION
// ============================================

function updateEmissions(raw) {
  const emissions = raw.emissions || {};
  const current = emissions.current || {};
  const waste = emissions.waste || {};
  const optimised = emissions.optimised || {};
  const equivalents = emissions.equivalents || {};

  const monthly = current.monthlyCO2Kg || 0;
  const annual = current.annualCO2Kg || (monthly * 12);

  document.getElementById('emissions-monthly').textContent = `${monthly.toFixed(2)} kg`;
  document.getElementById('emissions-annual').textContent = `${annual.toFixed(2)} kg annually`;

  // Breakdown - use actual waste data
  const wasteEmissions = waste.wastedCO2Kg || 0;
  const computeEmissions = monthly - wasteEmissions;

  document.getElementById('emissions-bandwidth').textContent = `${wasteEmissions.toFixed(3)} kg`;
  document.getElementById('emissions-bandwidth-bar').style.width = `${monthly > 0 ? (wasteEmissions / monthly) * 100 : 0}%`;

  document.getElementById('emissions-compute').textContent = `${computeEmissions.toFixed(2)} kg`;
  document.getElementById('emissions-compute-bar').style.width = `${monthly > 0 ? (computeEmissions / monthly) * 100 : 0}%`;

  // Trees equivalent from actual data
  const trees = equivalents.treesNeeded || (annual / 22).toFixed(1);
  document.getElementById('emissions-trees').textContent = trees;

  // Potential savings from optimised data
  const savingsMonthly = optimised.potentialSavingsKg || wasteEmissions;
  const savingsPercent = optimised.potentialSavingsPercent || (monthly > 0 ? (wasteEmissions / monthly) * 100 : 0);
  document.getElementById('emissions-savings').textContent = `${savingsMonthly.toFixed(3)} kg`;
  document.getElementById('emissions-savings-annual').textContent = `${(savingsMonthly * 12).toFixed(3)} kg`;
  document.getElementById('emissions-savings-percent').textContent = `${savingsPercent.toFixed(1)}%`;
}

// ============================================
// FIX MODULES
// ============================================

async function loadFixModules() {
  if (!currentProject) return;

  const fixPanel = document.getElementById('fix-panel');

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

    if (!data.success || !data.status || !data.status.modules || data.status.modules.length === 0) {
      fixPanel.innerHTML = `
        <div class="text-center text-muted py-4">
          <i class="bi bi-check-circle text-success"></i>
          <p class="mt-2 mb-0">No fixes available</p>
        </div>`;
      return;
    }

    fixPanel.innerHTML = data.status.modules.map(mod => `
      <div class="fix-module">
        <div class="fix-module-header">
          <span class="fix-module-name">${escapeHtml(mod.name)}</span>
          <span class="fix-module-confidence ${(mod.confidence || 'medium').toLowerCase()}">${mod.confidence || 'Medium'}</span>
        </div>
        <p class="text-muted small mb-2">${escapeHtml(mod.description || '')}</p>
        <small class="text-muted d-block mb-2">${mod.issueCount || 0} issues found</small>
        <div class="d-flex gap-2">
          <button class="btn btn-sm btn-outline-primary" onclick="previewFix('${mod.id}')">
            <i class="bi bi-eye"></i> Preview
          </button>
          <button class="btn btn-sm btn-primary" onclick="applyFix('${mod.id}')">
            <i class="bi bi-check"></i> Apply
          </button>
        </div>
      </div>
    `).join('');
  } catch (error) {
    console.error('Failed to load fixes:', error);
    fixPanel.innerHTML = `<div class="text-center text-muted py-4">Failed to load fixes</div>`;
  }
}

async function previewFix(moduleId) {
  try {
    const res = await fetch(`/api/fix/preview/${moduleId}/${encodeURIComponent(currentProject)}`);
    const data = await res.json();

    if (data.success) {
      alert(`Preview for ${moduleId}:\n\n${JSON.stringify(data.preview, null, 2)}`);
    } else {
      showToast('Error', data.error || 'Preview failed', 'danger');
    }
  } catch (error) {
    showToast('Error', 'Failed to preview fix', 'danger');
  }
}

async function applyFix(moduleId) {
  if (!confirm(`Apply fix: ${moduleId}?`)) return;

  try {
    const res = await fetch('/api/fix/apply', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ projectPath: currentProject, moduleId })
    });
    const data = await res.json();

    if (data.success) {
      showToast('Success', `Fix applied: ${moduleId}`, 'success');
      await loadFixModules();
    } else {
      showToast('Error', data.error || 'Apply failed', 'danger');
    }
  } catch (error) {
    showToast('Error', 'Failed to apply fix', 'danger');
  }
}

// ============================================
// QUARANTINE
// ============================================

async function loadQuarantine() {
  if (!currentProject) return;

  const panel = document.getElementById('quarantine-panel');

  try {
    const res = await fetch(`/api/quarantine/${encodeURIComponent(currentProject)}`);
    const data = await res.json();

    if (!data.success || !data.sessions || data.sessions.length === 0) {
      panel.innerHTML = `<p class="text-muted text-center mb-0">No quarantined files</p>`;
      return;
    }

    panel.innerHTML = data.sessions.map(session => `
      <div class="quarantine-item">
        <div class="d-flex justify-content-between align-items-center mb-1">
          <small class="text-muted">${formatDate(session.timestamp)}</small>
          <span class="badge bg-secondary">${session.fileCount || 0} files</span>
        </div>
        <div class="d-flex gap-2 mt-2">
          <button class="btn btn-sm btn-outline-warning" onclick="restoreSession('${session.id}')">
            <i class="bi bi-arrow-counterclockwise"></i> Restore
          </button>
          <button class="btn btn-sm btn-outline-danger" onclick="purgeSession('${session.id}')">
            <i class="bi bi-trash"></i>
          </button>
        </div>
      </div>
    `).join('');
  } catch (error) {
    console.error('Failed to load quarantine:', error);
    panel.innerHTML = `<p class="text-muted text-center mb-0">Failed to load</p>`;
  }
}

async function restoreSession(sessionId) {
  if (!confirm('Restore quarantined files?')) return;

  try {
    const res = await fetch('/api/quarantine/restore', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ projectPath: currentProject, sessionId })
    });
    const data = await res.json();

    if (data.success) {
      showToast('Success', 'Files restored', 'success');
      await loadQuarantine();
    } else {
      showToast('Error', data.error || 'Restore failed', 'danger');
    }
  } catch (error) {
    showToast('Error', 'Failed to restore', 'danger');
  }
}

async function purgeSession(sessionId) {
  if (!confirm('Permanently delete quarantined files?')) return;

  try {
    const res = await fetch('/api/quarantine/purge', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ projectPath: currentProject, sessionId })
    });
    const data = await res.json();

    if (data.success) {
      showToast('Success', 'Session purged', 'success');
      await loadQuarantine();
    } else {
      showToast('Error', data.error || 'Purge failed', 'danger');
    }
  } catch (error) {
    showToast('Error', 'Failed to purge', 'danger');
  }
}

// ============================================
// SCAN HISTORY
// ============================================

async function loadScanHistory() {
  if (!currentProject) return;

  try {
    const res = await fetch(`/api/scans?project=${encodeURIComponent(currentProject)}&limit=20&includeRaw=1`);
    const data = await res.json();

    const tbody = document.getElementById('scan-history');

    if (!data.success || !data.scans || data.scans.length === 0) {
      tbody.innerHTML = `<tr><td colspan="7" class="text-center text-muted py-4">No scans yet</td></tr>`;
      return;
    }

    scanHistory = data.scans;

    tbody.innerHTML = data.scans.map(scan => {
      const raw = scan.raw_data ? JSON.parse(scan.raw_data) : {};
      const score = raw.healthScore?.score || scan.score || 0;
      const waste = raw.summary?.wastePercent || 0;
      const security = (raw.security?.vulnerabilities || []).length;
      const outdated = (raw.outdated || []).length;
      const co2 = raw.emissions?.monthlyCO2 || 0;

      return `
        <tr>
          <td>${formatDate(scan.created_at)}</td>
          <td><span class="badge ${getScoreBadgeClass(score)}">${score}</span></td>
          <td>${waste.toFixed(1)}%</td>
          <td>${security}</td>
          <td>${outdated}</td>
          <td>${co2.toFixed(2)} kg</td>
          <td>
            <button class="btn btn-sm btn-outline-secondary" onclick="viewScan('${scan.id}')">
              <i class="bi bi-eye"></i>
            </button>
          </td>
        </tr>
      `;
    }).join('');

    // Update trend chart
    updateTrendChart(data.scans);
  } catch (error) {
    console.error('Failed to load scan history:', error);
  }
}

function viewScan(scanId) {
  const scan = scanHistory.find(s => s.id === scanId);
  if (scan) {
    currentScan = scan;
    loadScanData();
    navigateToSection('overview');
  }
}

// ============================================
// TREND CHART
// ============================================

function updateTrendChart(scans) {
  const canvas = document.getElementById('trend-chart');
  const emptyMsg = document.getElementById('chart-empty');

  if (!canvas || scans.length < 2) {
    if (emptyMsg) emptyMsg.classList.remove('d-none');
    return;
  }

  if (emptyMsg) emptyMsg.classList.add('d-none');

  // Prepare data (reverse to show oldest first)
  const sortedScans = [...scans].reverse().slice(-30);
  const labels = sortedScans.map(s => formatDateShort(s.created_at));
  const scores = sortedScans.map(s => {
    const raw = s.raw_data ? JSON.parse(s.raw_data) : {};
    return raw.healthScore?.score || s.score || 0;
  });
  const waste = sortedScans.map(s => {
    const raw = s.raw_data ? JSON.parse(s.raw_data) : {};
    return raw.summary?.wastePercent || 0;
  });

  if (trendChart) {
    trendChart.destroy();
  }

  trendChart = new Chart(canvas, {
    type: 'line',
    data: {
      labels,
      datasets: [
        {
          label: 'Score',
          data: scores,
          borderColor: '#58a6ff',
          backgroundColor: 'rgba(88, 166, 255, 0.1)',
          tension: 0.3,
          fill: true,
          yAxisID: 'y'
        },
        {
          label: 'Waste %',
          data: waste,
          borderColor: '#d29922',
          backgroundColor: 'rgba(210, 153, 34, 0.1)',
          tension: 0.3,
          fill: false,
          yAxisID: 'y1'
        }
      ]
    },
    options: {
      responsive: true,
      maintainAspectRatio: false,
      interaction: {
        mode: 'index',
        intersect: false
      },
      plugins: {
        legend: {
          position: 'top',
          labels: { color: '#8b949e' }
        }
      },
      scales: {
        x: {
          ticks: { color: '#8b949e' },
          grid: { color: '#30363d' }
        },
        y: {
          type: 'linear',
          display: true,
          position: 'left',
          min: 0,
          max: 100,
          ticks: { color: '#8b949e' },
          grid: { color: '#30363d' }
        },
        y1: {
          type: 'linear',
          display: true,
          position: 'right',
          min: 0,
          ticks: { color: '#8b949e' },
          grid: { drawOnChartArea: false }
        }
      }
    }
  });
}

// ============================================
// RESCAN
// ============================================

async function rescanProject() {
  if (!currentProject) {
    showToast('Error', 'No project selected', 'warning');
    return;
  }

  const btn = document.querySelector('.sidebar-footer .btn');
  const originalHtml = btn.innerHTML;
  btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span> Scanning...';
  btn.disabled = true;

  try {
    const res = await fetch('/api/scan', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ projectPath: currentProject })
    });
    const data = await res.json();

    if (data.success) {
      showToast('Success', 'Scan complete!', 'success');
      currentScan = data.scan;
      await loadScanData();
    } else {
      showToast('Error', data.error || 'Scan failed', 'danger');
    }
  } catch (error) {
    showToast('Error', 'Scan failed: ' + error.message, 'danger');
  } finally {
    btn.innerHTML = originalHtml;
    btn.disabled = false;
  }
}

// ============================================
// EXPANDED CONTENT RENDERERS
// ============================================

function renderVulnerabilityExpanded(vuln) {
  const usage = vuln.usage || vuln.usageAnalysis || {};
  const evidence = [];

  // Actual risk assessment
  if (usage.actualRisk) {
    evidence.push(EvidenceBlock({
      type: usage.actualRisk === 'high' ? 'security' : 'info',
      title: 'Actual Risk Assessment',
      description: usage.riskExplanation || `Risk level: ${usage.actualRisk}`,
      confidence: usage.confidence || 'medium'
    }));
  }

  // Usage locations
  if (usage.usageLocations && usage.usageLocations.length > 0) {
    evidence.push(EvidenceBlock({
      type: 'usage',
      title: 'Vulnerable Code Paths',
      items: usage.usageLocations.map(loc => ({
        file: loc.file,
        line: loc.line,
        context: loc.context
      })),
      confidence: usage.confidence
    }));
  }

  // If no usage found
  if (usage.isUsed === false) {
    evidence.push(EvidenceBlock({
      type: 'success',
      title: 'Usage Analysis',
      description: 'This vulnerable package does not appear to be used in your codebase, reducing actual risk.',
      confidence: 'high'
    }));
  }

  // CVE details
  if (vuln.cve || vuln.cveId) {
    evidence.push(`
      <div class="evidence-block evidence-info">
        <div class="evidence-header">
          <i class="bi bi-shield-exclamation"></i>
          <span class="evidence-title">CVE Details</span>
        </div>
        <div class="evidence-content">
          <p><strong>CVE:</strong> ${escapeHtml(vuln.cve || vuln.cveId)}</p>
          ${vuln.cwes ? `<p><strong>CWEs:</strong> ${vuln.cwes.join(', ')}</p>` : ''}
          ${vuln.cvss ? `<p><strong>CVSS Score:</strong> ${vuln.cvss}</p>` : ''}
        </div>
      </div>
    `);
  }

  // Recommendation
  const recommendation = {
    title: 'Fix This Vulnerability',
    priority: vuln.severity || 'medium',
    effort: 'low',
    commands: []
  };

  if (vuln.fixedIn) {
    recommendation.description = `Update to version ${vuln.fixedIn} or later to fix this vulnerability.`;
    recommendation.commands.push(`npm update ${vuln.package || vuln.name}`);
  } else if (vuln.recommendation) {
    recommendation.description = vuln.recommendation;
  }

  if (vuln.url || vuln.references) {
    recommendation.links = [];
    if (vuln.url) recommendation.links.push({ url: vuln.url, text: 'Advisory' });
    if (vuln.references) {
      vuln.references.forEach(ref => recommendation.links.push({ url: ref, text: 'Reference' }));
    }
  }

  return `
    <div class="expanded-content-grid">
      <div>
        <div class="expanded-content-section">
          <h6>Evidence</h6>
          ${evidence.join('')}
        </div>
      </div>
      <div>
        <div class="expanded-content-section">
          <h6>Recommendation</h6>
          ${RecommendationBlock(recommendation)}
        </div>
      </div>
    </div>
  `;
}

function renderOutdatedExpanded(pkg) {
  const content = [];

  // Health indicator
  if (pkg.health) {
    content.push(`
      <div class="expanded-content-section">
        <h6>Package Health</h6>
        ${HealthIndicator(pkg.health)}
      </div>
    `);
  }

  // Changelog highlights
  if (pkg.changelog) {
    content.push(`
      <div class="expanded-content-section">
        <h6>What's New</h6>
        ${ChangelogBlock(pkg.changelog)}
      </div>
    `);
  }

  // Security fixes
  if (pkg.securityFixes && pkg.securityFixes.length > 0) {
    content.push(`
      <div class="expanded-content-section">
        <h6>Security Fixes in Update</h6>
        ${EvidenceBlock({
          type: 'security',
          title: `${pkg.securityFixes.length} Security Fix${pkg.securityFixes.length > 1 ? 'es' : ''}`,
          items: pkg.securityFixes.map(fix => ({
            text: `${fix.severity}: ${fix.title || fix.description}`
          }))
        })}
      </div>
    `);
  }

  // Migration guide
  if (pkg.migration || pkg.migrationGuide) {
    const migration = pkg.migration || pkg.migrationGuide;
    content.push(`
      <div class="expanded-content-section">
        <h6>Migration</h6>
        ${MigrationGuideBlock({
          fromVersion: pkg.current || pkg.version,
          toVersion: pkg.latest,
          effort: pkg.updateEffort || migration.effort,
          steps: migration.steps || [],
          links: migration.links || []
        })}
      </div>
    `);
  }

  // Cost impact
  if (pkg.costImpact) {
    content.push(`
      <div class="expanded-content-section">
        <h6>Cost of Not Updating</h6>
        ${CostImpactBlock(pkg.costImpact)}
      </div>
    `);
  }

  // Recommendation
  const recommendation = {
    title: `Update ${pkg.name}`,
    priority: pkg.updateType === 'major' ? 'high' : pkg.updateType === 'minor' ? 'medium' : 'low',
    effort: pkg.updateEffort || (pkg.updateType === 'major' ? 'high' : 'low'),
    commands: [`npm update ${pkg.name}`],
    description: pkg.updateType === 'major'
      ? 'This is a major version update. Review breaking changes before updating.'
      : 'This update should be safe to apply.'
  };

  content.push(`
    <div class="expanded-content-section">
      <h6>Action</h6>
      ${RecommendationBlock(recommendation)}
    </div>
  `);

  return `<div class="expanded-content-grid single-column">${content.join('')}</div>`;
}

function renderUnusedDepExpanded(dep) {
  const content = [];

  // Evidence of non-usage
  const evidence = {
    type: 'file',
    title: 'Why We Think It\'s Unused',
    confidence: dep.confidence || 'medium',
    items: []
  };

  if (dep.lastUsed) {
    evidence.items.push({ text: `Last used: ${formatDate(dep.lastUsed)}` });
  }

  if (dep.searchedPatterns) {
    evidence.items.push({ text: `Searched for: ${dep.searchedPatterns.join(', ')}` });
  }

  if (dep.potentialUsage && dep.potentialUsage.length > 0) {
    evidence.items.push({ text: `Potential references found but not confirmed: ${dep.potentialUsage.length}` });
  } else {
    evidence.items.push({ text: 'No imports or requires found in codebase' });
  }

  content.push(`
    <div class="expanded-content-section">
      <h6>Evidence</h6>
      ${EvidenceBlock(evidence)}
    </div>
  `);

  // Git history
  if (dep.git || dep.gitHistory) {
    content.push(`
      <div class="expanded-content-section">
        <h6>Git History</h6>
        ${GitHistoryBlock(dep.git || dep.gitHistory)}
      </div>
    `);
  }

  // Cost impact
  if (dep.costImpact || dep.sizeBytes) {
    content.push(`
      <div class="expanded-content-section">
        <h6>Cost Impact</h6>
        ${CostImpactBlock({
          bandwidth: dep.sizeBytes,
          co2Monthly: dep.costImpact?.co2Monthly,
          potentialSavings: dep.costImpact?.monthlySavings,
          potentialSavingsAnnual: dep.costImpact?.annualSavings,
          description: `This unused dependency adds ${formatBytes(dep.sizeBytes || 0)} to your project.`
        })}
      </div>
    `);
  }

  // Recommendation
  const recommendation = {
    title: `Remove ${dep.name}`,
    priority: 'medium',
    effort: 'low',
    commands: [`npm uninstall ${dep.name}`],
    description: 'Remove this unused dependency to reduce bundle size and maintenance burden.'
  };

  if (dep.alternatives && dep.alternatives.length > 0) {
    recommendation.alternatives = dep.alternatives;
  }

  content.push(`
    <div class="expanded-content-section">
      <h6>Recommendation</h6>
      ${RecommendationBlock(recommendation)}
    </div>
  `);

  return `<div class="expanded-content-grid single-column">${content.join('')}</div>`;
}

function renderDeadCodeExpanded(file) {
  const content = [];

  // Dead exports evidence
  if (file.deadExports && file.deadExports.length > 0) {
    content.push(`
      <div class="expanded-content-section">
        <h6>Unused Exports</h6>
        ${EvidenceBlock({
          type: 'export',
          title: `${file.deadExports.length} Unused Export${file.deadExports.length > 1 ? 's' : ''}`,
          items: file.deadExports.map(exp => ({
            text: `${exp.type || 'export'} ${exp.name}${exp.line ? ` (line ${exp.line})` : ''}`
          })),
          confidence: file.confidence || 'medium'
        })}
      </div>
    `);
  }

  // If fully dead file
  if (file.isOrphan || file.fullyDead) {
    content.push(`
      <div class="expanded-content-section">
        <h6>Analysis</h6>
        ${EvidenceBlock({
          type: 'warning',
          title: 'Orphan File',
          description: 'This file is not imported by any other file in the project and does not appear to be an entry point.',
          confidence: file.confidence || 'high'
        })}
      </div>
    `);
  }

  // Git history
  if (file.git || file.gitHistory) {
    content.push(`
      <div class="expanded-content-section">
        <h6>Git History</h6>
        ${GitHistoryBlock(file.git || file.gitHistory)}
      </div>
    `);
  }

  // Cost impact
  if (file.costImpact || file.sizeBytes) {
    content.push(`
      <div class="expanded-content-section">
        <h6>Cost Impact</h6>
        ${CostImpactBlock({
          bandwidth: file.sizeBytes,
          co2Monthly: file.costImpact?.co2Monthly,
          potentialSavings: file.costImpact?.monthlySavings,
          description: `This dead code adds ${formatBytes(file.sizeBytes || 0)} to your codebase.`
        })}
      </div>
    `);
  }

  // Recommendation
  const recommendation = {
    title: file.isOrphan ? 'Delete This File' : 'Remove Unused Exports',
    priority: 'low',
    effort: 'low',
    description: file.isOrphan
      ? 'This file appears to be completely unused. Consider deleting it after verification.'
      : 'Remove the unused exports to reduce bundle size.',
    steps: file.isOrphan
      ? ['Verify the file is not dynamically imported', 'Check for any side effects', 'Delete the file']
      : ['Remove or refactor the unused exports', 'Run tests to verify nothing breaks']
  };

  content.push(`
    <div class="expanded-content-section">
      <h6>Recommendation</h6>
      ${RecommendationBlock(recommendation)}
    </div>
  `);

  return `<div class="expanded-content-grid single-column">${content.join('')}</div>`;
}

function renderAssetExpanded(asset) {
  const content = [];

  // Asset info
  const assetInfo = [];
  if (asset.dimensions) {
    assetInfo.push(`Dimensions: ${asset.dimensions.width}x${asset.dimensions.height}`);
  }
  if (asset.format) {
    assetInfo.push(`Format: ${asset.format.toUpperCase()}`);
  }
  if (asset.colorDepth) {
    assetInfo.push(`Color depth: ${asset.colorDepth}-bit`);
  }
  if (asset.hasAlpha !== undefined) {
    assetInfo.push(`Alpha channel: ${asset.hasAlpha ? 'Yes' : 'No'}`);
  }

  if (assetInfo.length > 0) {
    content.push(`
      <div class="expanded-content-section">
        <h6>Asset Details</h6>
        ${EvidenceBlock({
          type: 'file',
          title: 'Technical Info',
          items: assetInfo.map(info => ({ text: info }))
        })}
      </div>
    `);
  }

  // Usage evidence
  if (asset.usage) {
    const usageEvidence = {
      type: asset.usage.isUsed ? 'usage' : 'warning',
      title: asset.usage.isUsed ? 'Usage Found' : 'No Usage Found',
      confidence: asset.usage.confidence || 'medium',
      items: []
    };

    if (asset.usage.references && asset.usage.references.length > 0) {
      usageEvidence.items = asset.usage.references.map(ref => ({
        file: ref.file,
        line: ref.line,
        context: ref.context
      }));
    } else {
      usageEvidence.description = 'No references to this asset were found in the codebase.';
    }

    content.push(`
      <div class="expanded-content-section">
        <h6>Usage Analysis</h6>
        ${EvidenceBlock(usageEvidence)}
      </div>
    `);
  }

  // Optimization opportunities
  if (asset.optimization) {
    const opt = asset.optimization;
    const optContent = [];

    if (opt.canCompress) {
      optContent.push(`Can be compressed (potential ${formatBytes(opt.compressedSize || 0)} savings)`);
    }
    if (opt.suggestedFormat) {
      optContent.push(`Consider converting to ${opt.suggestedFormat.toUpperCase()}`);
    }
    if (opt.canResize) {
      optContent.push('Image appears oversized for its usage');
    }

    if (optContent.length > 0) {
      content.push(`
        <div class="expanded-content-section">
          <h6>Optimization</h6>
          ${EvidenceBlock({
            type: 'info',
            title: 'Potential Optimizations',
            items: optContent.map(item => ({ text: item }))
          })}
        </div>
      `);
    }
  }

  // Git history
  if (asset.git || asset.gitHistory) {
    content.push(`
      <div class="expanded-content-section">
        <h6>Git History</h6>
        ${GitHistoryBlock(asset.git || asset.gitHistory)}
      </div>
    `);
  }

  // Cost impact
  if (asset.costImpact || asset.sizeBytes) {
    content.push(`
      <div class="expanded-content-section">
        <h6>Cost Impact</h6>
        ${CostImpactBlock({
          bandwidth: asset.sizeBytes,
          bandwidthMonthly: asset.costImpact?.bandwidthMonthly,
          co2Monthly: asset.costImpact?.co2Monthly,
          potentialSavings: asset.costImpact?.potentialSavings,
          description: asset.usage?.isUsed === false
            ? 'This unused asset is still being served to users.'
            : 'Bandwidth cost per month based on estimated traffic.'
        })}
      </div>
    `);
  }

  // Recommendation
  let recommendation;
  if (asset.usage?.isUsed === false) {
    recommendation = {
      title: 'Remove Unused Asset',
      priority: 'medium',
      effort: 'low',
      description: 'This asset is not referenced in the codebase. Remove it to reduce build size.',
      commands: [`rm "${asset.relativePath || asset.path}"`]
    };
  } else if (asset.optimization?.suggestedFormat) {
    recommendation = {
      title: `Convert to ${asset.optimization.suggestedFormat.toUpperCase()}`,
      priority: 'low',
      effort: 'medium',
      description: `Converting to ${asset.optimization.suggestedFormat} could reduce file size significantly.`
    };
  }

  if (recommendation) {
    content.push(`
      <div class="expanded-content-section">
        <h6>Recommendation</h6>
        ${RecommendationBlock(recommendation)}
      </div>
    `);
  }

  return `<div class="expanded-content-grid single-column">${content.join('')}</div>`;
}

// ============================================
// QUICK FIXES
// ============================================

async function loadQuickFixes() {
  if (!currentScan) return;

  const container = document.getElementById('quick-fixes-list');
  if (!container) return;

  const raw = currentScan.raw_data ? JSON.parse(currentScan.raw_data) : {};
  const details = raw.details || {};
  const fixes = [];

  // Collect quick fixes from various sources
  // Unused dependencies
  (details.unusedDeps || []).forEach(dep => {
    if (dep.confidence === 'high' || !dep.confidence) {
      fixes.push({
        id: `unused-dep-${dep.name}`,
        category: 'unused-dep',
        title: `Remove ${dep.name}`,
        description: 'Unused dependency can be safely removed',
        confidence: dep.confidence || 'high',
        effort: 'low',
        commands: [`npm uninstall ${dep.name}`],
        savings: {
          bytes: dep.sizeBytes || 50000,
          co2: dep.costImpact?.co2Monthly
        }
      });
    }
  });

  // Dead code files
  const deadCode = details.deadCode || {};
  (deadCode.fullyDeadFiles || deadCode.orphanFiles || []).slice(0, 10).forEach(file => {
    fixes.push({
      id: `dead-code-${file.relativePath || file.file}`,
      category: 'dead-code',
      title: `Remove ${(file.relativePath || file.file).split('/').pop()}`,
      description: 'Orphan file not imported anywhere',
      confidence: file.confidence || 'high',
      effort: 'low',
      files: [file.relativePath || file.file],
      savings: {
        bytes: file.sizeBytes || 0
      }
    });
  });

  // Unused assets
  (details.unusedAssets || []).slice(0, 10).forEach(asset => {
    fixes.push({
      id: `unused-asset-${asset.relativePath || asset.path}`,
      category: 'unused-asset',
      title: `Remove ${(asset.relativePath || asset.path).split('/').pop()}`,
      description: 'Asset not referenced in codebase',
      confidence: asset.confidence || 'medium',
      effort: 'low',
      files: [asset.relativePath || asset.path],
      savings: {
        bytes: asset.sizeBytes || 0,
        co2: asset.costImpact?.co2Monthly
      }
    });
  });

  // Sort by savings
  fixes.sort((a, b) => (b.savings?.bytes || 0) - (a.savings?.bytes || 0));

  // Update badge
  const badge = document.getElementById('quick-fixes-badge');
  if (badge) {
    badge.textContent = fixes.length;
    badge.style.display = fixes.length > 0 ? 'inline-block' : 'none';
  }

  if (fixes.length === 0) {
    container.innerHTML = `
      <div class="text-center text-muted py-4">
        <i class="bi bi-check-circle text-success display-6"></i>
        <p class="mt-2 mb-0">No quick fixes available</p>
      </div>
    `;
    return;
  }

  container.innerHTML = fixes.map(fix => QuickFixCard(fix)).join('');
}

async function previewQuickFix(fixId) {
  showToast('Preview', `Preview for ${fixId} - Coming soon`, 'info');
}

async function applyQuickFix(fixId) {
  if (!confirm(`Apply quick fix: ${fixId}?`)) return;
  showToast('Applied', `Quick fix ${fixId} applied - Coming soon`, 'success');
}

// ============================================
// UTILITIES
// ============================================

function escapeHtml(str) {
  if (!str) return '';
  const div = document.createElement('div');
  div.textContent = str;
  return div.innerHTML;
}

function formatBytes(bytes) {
  if (bytes === 0) return '0 B';
  const k = 1024;
  const sizes = ['B', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}

function formatDate(dateStr) {
  if (!dateStr) return '-';
  const d = new Date(dateStr);
  return d.toLocaleDateString('en-GB', {
    day: 'numeric', month: 'short', year: 'numeric',
    hour: '2-digit', minute: '2-digit'
  });
}

function formatDateShort(dateStr) {
  if (!dateStr) return '-';
  const d = new Date(dateStr);
  return d.toLocaleDateString('en-GB', { day: 'numeric', month: 'short' });
}

function getGrade(score) {
  if (score >= 90) return 'A';
  if (score >= 80) return 'B';
  if (score >= 70) return 'C';
  if (score >= 60) return 'D';
  return 'F';
}

function getScoreDescription(score) {
  if (score >= 90) return 'Excellent - minimal issues';
  if (score >= 80) return 'Good - minor issues';
  if (score >= 70) return 'Fair - some concerns';
  if (score >= 60) return 'Poor - significant issues';
  return 'Critical - major problems';
}

function getScoreBadgeClass(score) {
  if (score >= 90) return 'bg-success';
  if (score >= 80) return 'bg-info';
  if (score >= 70) return 'bg-warning text-dark';
  if (score >= 60) return 'bg-orange';
  return 'bg-danger';
}

function calculateWasteScore(raw) {
  const waste = raw.summary?.wastePercent || 0;
  // 0% waste = 30 points, 100% waste = 0 points
  return Math.max(0, Math.round(30 - (waste * 0.3)));
}

function calculateSecurityScore(raw) {
  const vulns = raw.security?.vulnerabilities || [];
  let deduction = 0;
  vulns.forEach(v => {
    const sev = (v.severity || '').toLowerCase();
    if (sev === 'critical') deduction += 20;
    else if (sev === 'high') deduction += 10;
    else if (sev === 'medium') deduction += 5;
    else deduction += 2;
  });
  return Math.max(0, 40 - deduction);
}

function calculateDepsScore(raw) {
  const outdated = raw.outdated || [];  // Array at top level
  let deduction = 0;
  outdated.forEach(pkg => {
    const type = (pkg.updateType || '').toLowerCase();
    if (type === 'major') deduction += 5;
    else if (type === 'minor') deduction += 2;
    else deduction += 1;
  });
  return Math.max(0, 20 - deduction);
}

function calculateEmissionsScore(raw) {
  const co2 = raw.emissions?.monthlyCO2 || 0;
  // Lower emissions = better score. 0 kg = 10 points, 10+ kg = 0 points
  if (co2 <= 0.5) return 10;
  if (co2 <= 1) return 8;
  if (co2 <= 2) return 6;
  if (co2 <= 5) return 4;
  if (co2 <= 10) return 2;
  return 0;
}

function copyCommand(cmd) {
  navigator.clipboard.writeText(cmd).then(() => {
    showToast('Copied', cmd, 'success');
  }).catch(err => {
    console.error('Copy failed:', err);
  });
}

function showToast(title, message, type = 'info') {
  const toastEl = document.getElementById('toast');
  const toastTitle = document.getElementById('toast-title');
  const toastBody = document.getElementById('toast-body');

  toastTitle.textContent = title;
  toastBody.textContent = message;

  // Update header color based on type
  const header = toastEl.querySelector('.toast-header');
  header.className = 'toast-header';
  if (type === 'success') header.classList.add('text-success');
  else if (type === 'danger') header.classList.add('text-danger');
  else if (type === 'warning') header.classList.add('text-warning');

  const toast = new bootstrap.Toast(toastEl);
  toast.show();
}

// Expose functions globally for onclick handlers
window.rescanProject = rescanProject;
window.previewFix = previewFix;
window.applyFix = applyFix;
window.restoreSession = restoreSession;
window.purgeSession = purgeSession;
window.viewScan = viewScan;
window.copyCommand = copyCommand;
window.navigateToSection = navigateToSection;
window.toggleRowExpand = toggleRowExpand;
window.previewQuickFix = previewQuickFix;
window.applyQuickFix = applyQuickFix;

// Make currentScan accessible for components
window.getCurrentScan = () => currentScan;
