<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>WPA Self-Service — Regression Dashboard</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="https://cdn.jsdelivr.net/npm/chart.js@4"></script>
  <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@3"></script>
  <style>
    body { font-family: 'Segoe UI', system-ui, sans-serif; }
    .status-pass { background: #e8f5e3; color: #2a8703; }
    .status-fail { background: #fde8e6; color: #ea1100; }
    .status-unknown { background: #f5f5f5; color: #74767c; }
    .status-cancelled { background: #fff8e1; color: #995213; }
    .status-dot { width: 12px; height: 12px; border-radius: 50%; display: inline-block; }
    .dot-pass { background: #2a8703; }
    .dot-fail { background: #ea1100; }
    .dot-unknown { background: #74767c; }
    .dot-cancelled { background: #ffc220; }
    #buildsTable tbody tr:hover { background: #f9fafb; }
  </style>
</head>
<body class="bg-white text-gray-800">

  <!-- Header -->
  <header class="bg-[#0053e2] text-white py-6 px-8 shadow-lg">
    <div class="max-w-7xl mx-auto flex items-center justify-between">
      <div>
        <h1 class="text-2xl font-bold">🎭 WPA Self-Service — Regression Dashboard</h1>
        <p class="text-blue-100 text-sm mt-1">Generated at <span id="fetchedAt"></span></p>
      </div>
      <div class="flex gap-4 text-sm">
        <span class="flex items-center gap-1"><span class="status-dot dot-pass"></span> Pass</span>
        <span class="flex items-center gap-1"><span class="status-dot dot-fail"></span> Fail</span>
        <span class="flex items-center gap-1"><span class="status-dot dot-cancelled"></span> Cancelled</span>
        <span class="flex items-center gap-1"><span class="status-dot dot-unknown"></span> Unknown</span>
      </div>
    </div>
  </header>

  <!-- Date range + filter bar -->
  <section class="bg-gray-50 border-b border-gray-200 px-8 py-4">
    <div class="max-w-7xl mx-auto flex flex-wrap items-center gap-4">
      <span class="text-sm font-semibold text-gray-600">Date range:</span>
      <div class="flex items-center gap-2">
        <input id="dateFrom" type="date"
               class="border border-gray-300 rounded px-3 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-[#0053e2]">
        <span class="text-gray-400">→</span>
        <input id="dateTo" type="date"
               class="border border-gray-300 rounded px-3 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-[#0053e2]">
      </div>
      <div class="flex gap-2">
        <button onclick="setRange(7)"  class="text-xs px-3 py-1.5 rounded border border-gray-300 hover:bg-white transition-colors" id="btn7">7d</button>
        <button onclick="setRange(14)" class="text-xs px-3 py-1.5 rounded border border-gray-300 hover:bg-white transition-colors" id="btn14">14d</button>
        <button onclick="setRange(30)" class="text-xs px-3 py-1.5 rounded border border-gray-300 hover:bg-white transition-colors" id="btn30">30d</button>
        <button onclick="setRangeAll()" class="text-xs px-3 py-1.5 rounded border border-gray-300 hover:bg-white transition-colors" id="btnAll">All</button>
      </div>
      <div class="w-px h-5 bg-gray-300 mx-1"></div>
      <select id="jobFilter" onchange="applyFilter()"
              class="border border-gray-300 rounded px-3 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-[#0053e2]">
        <option value="">All jobs</option>
      </select>
      <select id="statusFilter" onchange="applyFilter()"
              class="border border-gray-300 rounded px-3 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-[#0053e2]">
        <option value="">All statuses</option>
        <option value="SUCCESS">Pass only</option>
        <option value="FAILURE">Fail only</option>
      </select>
      <span class="text-sm text-gray-500 ml-auto" id="rangeLabel"></span>
    </div>
  </section>

  <!-- Summary Cards -->
  <section class="max-w-7xl mx-auto px-8 py-6">
    <div class="grid grid-cols-2 md:grid-cols-4 gap-4" id="summaryCards"></div>
  </section>

  <!-- Pass Rate Trend Chart -->
  <section class="max-w-7xl mx-auto px-8 pb-6">
    <div class="bg-white rounded-lg border border-gray-200 p-4 shadow-sm">
      <h3 class="text-sm font-semibold text-gray-600 mb-2">Pass Rate Trend — by Job</h3>
      <p class="text-xs text-gray-400 mb-3">% tests passing per build, grouped by job</p>
      <div style="height: 280px; position: relative;"><canvas id="trendChart"></canvas></div>
    </div>
  </section>

  <!-- Unified Builds Table -->
  <section class="max-w-7xl mx-auto px-8 pb-6">
    <div class="flex items-center justify-between mb-3">
      <h2 class="text-lg font-bold text-gray-800">Build History</h2>
      <span class="text-sm text-gray-500" id="tableLabel"></span>
    </div>
    <div class="overflow-x-auto rounded-lg border border-gray-200 shadow-sm">
      <table class="w-full text-sm" id="buildsTable">
        <thead class="bg-gray-50">
          <tr>
            <th class="text-left px-4 py-2 font-medium text-gray-600">Job</th>
            <th class="text-left px-4 py-2 font-medium text-gray-600">Flow</th>
            <th class="text-center px-4 py-2 font-medium text-gray-600">Build #</th>
            <th class="text-center px-4 py-2 font-medium text-gray-600">Status</th>
            <th class="text-center px-4 py-2 font-medium text-gray-600">Ran At</th>
            <th class="text-center px-4 py-2 font-medium text-gray-600">⏱ Duration</th>
            <th class="text-center px-4 py-2 font-medium text-gray-600">✅ Passed</th>
            <th class="text-center px-4 py-2 font-medium text-gray-600">❌ Failed</th>
            <th class="text-center px-4 py-2 font-medium text-gray-600">🎲 Flaky</th>
            <th class="text-center px-4 py-2 font-medium text-gray-600">⏭️ Skipped</th>
            <th class="text-center px-4 py-2 font-medium text-gray-600">Report</th>
          </tr>
        </thead>
        <tbody id="buildsBody"></tbody>
      </table>
    </div>
  </section>

  <!-- AI Analysis -->
  <section class="max-w-7xl mx-auto px-8 pb-6" id="aiAnalysisSection"></section>

  <!-- Failure Details -->
  <section class="max-w-7xl mx-auto px-8 pb-12" id="analysisSection"></section>

  <script>
    const allRows   = __ROWS_JSON__;
    const fetchedAt = "__FETCHED_AT__";
    const embeddedDays = __DAYS__;
    const aiAnalysis = __AI_ANALYSIS_JSON__;

    document.getElementById('fetchedAt').textContent = new Date(fetchedAt).toLocaleString();

    // ── Date utilities ──────────────────────────────────────────────────────
    function toDateStr(iso) {
      // Returns "YYYY-MM-DD" in local time from an ISO string
      if (!iso) return '';
      return new Date(iso).toLocaleDateString('en-CA'); // "YYYY-MM-DD"
    }

    function dateBounds() {
      const dates = allRows.map(r => r.startTime).filter(Boolean).map(toDateStr).sort();
      return { min: dates[0] || '', max: dates[dates.length - 1] || '' };
    }

    function setRange(days) {
      const to = new Date();
      const from = new Date(to.getTime() - days * 86400000);
      document.getElementById('dateFrom').value = from.toLocaleDateString('en-CA');
      document.getElementById('dateTo').value   = to.toLocaleDateString('en-CA');
      highlightBtn(days === 7 ? 'btn7' : days === 14 ? 'btn14' : 'btn30');
      applyFilter();
    }

    function setRangeAll() {
      const b = dateBounds();
      document.getElementById('dateFrom').value = b.min;
      document.getElementById('dateTo').value   = b.max;
      highlightBtn('btnAll');
      applyFilter();
    }

    function highlightBtn(activeId) {
      ['btn7','btn14','btn30','btnAll'].forEach(id => {
        const el = document.getElementById(id);
        el.classList.toggle('bg-[#0053e2]', id === activeId);
        el.classList.toggle('text-white',   id === activeId);
        el.classList.toggle('border-[#0053e2]', id === activeId);
      });
    }

    // ── Filtered rows ───────────────────────────────────────────────────────
    function getVisibleRows() {
      const from   = document.getElementById('dateFrom').value;
      const to     = document.getElementById('dateTo').value;
      const job    = document.getElementById('jobFilter').value;
      const status = document.getElementById('statusFilter').value;

      return allRows.filter(r => {
        const ds = toDateStr(r.startTime);
        if (from && ds < from) return false;
        if (to   && ds > to)   return false;
        if (job  && r.jobName !== job) return false;
        if (status && r.buildStatus !== status) return false;
        return true;
      });
    }

    // ── Summary cards ───────────────────────────────────────────────────────
    function renderCards(rows) {
      const totalPassed  = rows.reduce((s, r) => s + (r.testsPassed  || 0), 0);
      const totalFailed  = rows.reduce((s, r) => s + (r.testsFailed  || 0), 0);
      const totalFlaky   = rows.reduce((s, r) => s + (r.testsFlaky   || 0), 0);
      const totalSkipped = rows.reduce((s, r) => s + (r.testsSkipped || 0), 0);
      const totalRun   = totalPassed + totalFailed;
      const passRate   = totalRun ? ((totalPassed / totalRun) * 100).toFixed(1) + '%' : '—';

      const cards = [
        { label: 'Tests Passed',    value: totalPassed.toLocaleString(),  color: 'border-[#2a8703]', bg: 'bg-green-50' },
        { label: 'Tests Failed',    value: totalFailed.toLocaleString(),  color: 'border-[#ea1100]', bg: 'bg-red-50' },
        { label: 'Flaky / Skipped', value: `${totalFlaky} / ${totalSkipped}`, color: 'border-[#ffc220]', bg: 'bg-yellow-50' },
        { label: 'Pass Rate',       value: passRate, color: 'border-[#0053e2]', bg: 'bg-blue-50' },
      ];
      const el = document.getElementById('summaryCards');
      el.innerHTML = '';
      cards.forEach(c => {
        el.innerHTML += `
          <div class="${c.bg} rounded-lg border-l-4 ${c.color} p-4 shadow-sm">
            <p class="text-xs text-gray-500 uppercase tracking-wide">${c.label}</p>
            <p class="text-3xl font-bold mt-1">${c.value}</p>
          </div>`;
      });
    }

    // ── Trend chart ─────────────────────────────────────────────────────────
    const JOB_COLORS = [
      '#0053e2','#ea1100','#2a8703','#ffc220','#7c3aed',
      '#db2777','#0891b2','#d97706','#16a34a','#dc2626',
    ];
    let trendChartInstance = null;

    function renderTrend(rows) {
      const jobNames = [...new Set(allRows.map(r => r.jobName))].sort();

      // For each job: collect (date, passRate) points sorted by date
      const datasets = jobNames.map((jn, i) => {
        const jobRows = rows
          .filter(r => r.jobName === jn && r.startTime && r.testsPassed !== null)
          .sort((a, b) => a.startTime.localeCompare(b.startTime));

        const points = jobRows.map(r => {
          const run = (r.testsPassed || 0) + (r.testsFailed || 0);
          return {
            x: new Date(r.startTime).getTime(),  // ms timestamp — unambiguous for time scale
            y: run ? +((r.testsPassed / run) * 100).toFixed(1) : null,
            buildNumber: r.buildNumber,
            dateLabel: toDateStr(r.startTime),
          };
        }).filter(p => p.y !== null);

        return {
          label: jn.replace('wpa-wmt-', ''),
          data: points,
          borderColor: JOB_COLORS[i % JOB_COLORS.length],
          backgroundColor: JOB_COLORS[i % JOB_COLORS.length] + '22',
          fill: false,
          tension: 0.3,
          pointRadius: 4,
          pointHoverRadius: 6,
        };
      });

      const ctx = document.getElementById('trendChart').getContext('2d');
      if (trendChartInstance) trendChartInstance.destroy();

      // Determine x-axis min/max from the current date filter inputs
      const fromVal = document.getElementById('dateFrom').value;
      const toVal   = document.getElementById('dateTo').value;

      trendChartInstance = new Chart(ctx, {
        type: 'line',
        data: { datasets },
        options: {
          responsive: true, maintainAspectRatio: false,
          plugins: {
            legend: { position: 'bottom' },
            tooltip: {
              callbacks: {
                title: items => items[0].raw.dateLabel,
                label: item => {
                  const raw = item.raw;
                  return ` ${item.dataset.label}: ${raw.y}%  (build #${raw.buildNumber})`;
                },
              },
            },
          },
          scales: {
            x: {
              type: 'time',
              time: { unit: 'day', tooltipFormat: 'yyyy-MM-dd', displayFormats: { day: 'MMM d' } },
              min: fromVal ? new Date(fromVal).getTime() : undefined,
              max: toVal   ? new Date(toVal + 'T23:59:59').getTime() : undefined,
              title: { display: true, text: 'Build Date' },
            },
            y: {
              min: 0, max: 100,
              title: { display: true, text: 'Pass Rate (%)' },
              ticks: { callback: v => v + '%' },
            },
          },
        },
      });
    }

    // ── Builds table ────────────────────────────────────────────────────────
    function renderTable(rows) {
      const tbody = document.getElementById('buildsBody');
      const label = document.getElementById('tableLabel');
      label.textContent = `${rows.length} build${rows.length !== 1 ? 's' : ''}`;

      const fmt = n => (n !== null && n !== undefined)
        ? `<span class="font-medium">${n}</span>`
        : '<span class="text-gray-400">—</span>';

      const fmtTime = iso => {
        if (!iso) return '<span class="text-gray-400">—</span>';
        const d = new Date(iso);
        const date = d.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' });
        const time = d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });
        return `<span class="text-gray-700">${date}</span><br><span class="text-gray-400 text-xs">${time}</span>`;
      };

      tbody.innerHTML = rows.map(r => {
        const statusClass = r.buildStatus === 'SUCCESS'   ? 'status-pass'
                          : r.buildStatus === 'FAILURE'   ? 'status-fail'
                          : r.buildStatus === 'CANCELLED' ? 'status-cancelled'
                          : 'status-unknown';
        const dotClass = r.buildStatus === 'SUCCESS'   ? 'dot-pass'
                       : r.buildStatus === 'FAILURE'   ? 'dot-fail'
                       : r.buildStatus === 'CANCELLED' ? 'dot-cancelled'
                       : 'dot-unknown';
        const shortJob = r.jobName.replace('wpa-wmt-', '');

        return `
          <tr class="border-t border-gray-100">
            <td class="px-4 py-2 text-xs font-mono">${shortJob}</td>
            <td class="px-4 py-2 text-xs text-gray-600">${r.flowName}</td>
            <td class="px-4 py-2 text-center text-xs">#${r.buildNumber || '?'}</td>
            <td class="px-4 py-2 text-center">
              <span class="inline-flex items-center gap-1.5 px-2 py-0.5 rounded-full text-xs font-medium ${statusClass}">
                <span class="status-dot ${dotClass}"></span> ${r.buildStatus}
              </span>
            </td>
            <td class="px-4 py-2 text-center text-xs leading-tight">${fmtTime(r.startTime)}</td>
            <td class="px-4 py-2 text-center text-xs text-gray-500">${r.duration || '<span class="text-gray-400">—</span>'}</td>
            <td class="px-4 py-2 text-center text-xs text-green-700">${fmt(r.testsPassed)}</td>
            <td class="px-4 py-2 text-center text-xs text-red-600">${fmt(r.testsFailed)}</td>
            <td class="px-4 py-2 text-center text-xs text-yellow-700">${fmt(r.testsFlaky)}</td>
            <td class="px-4 py-2 text-center text-xs text-gray-500">${fmt(r.testsSkipped)}</td>
            <td class="px-4 py-2 text-center">
              <a href="${r.reportUrl}" target="_blank" rel="noopener"
                 class="text-[#0053e2] hover:text-[#003d9e] text-xs underline"
                 aria-label="View report for ${r.flowName} #${r.buildNumber}">View</a>
            </td>
          </tr>`;
      }).join('');
    }

    // ── Range label ─────────────────────────────────────────────────────────
    function renderRangeLabel(rows) {
      const from = document.getElementById('dateFrom').value;
      const to   = document.getElementById('dateTo').value;
      const jobs = new Set(rows.map(r => r.jobName)).size;
      document.getElementById('rangeLabel').textContent =
        `${rows.length} build${rows.length !== 1 ? 's' : ''} · ${jobs} job${jobs !== 1 ? 's' : ''} · ${from} → ${to}`;
    }

    // ── Master filter/render ─────────────────────────────────────────────────
    function applyFilter() {
      const rows = getVisibleRows();
      renderCards(rows);
      renderTrend(rows);
      renderTable(rows);
      renderRangeLabel(rows);
      renderFailureDetails(rows);
    }

    // ── Populate job filter dropdown ─────────────────────────────────────────
    function populateJobFilter() {
      const sel = document.getElementById('jobFilter');
      const jobs = [...new Set(allRows.map(r => r.jobName))].sort();
      jobs.forEach(jn => {
        const opt = document.createElement('option');
        opt.value = jn;
        opt.textContent = jn.replace('wpa-wmt-', '');
        sel.appendChild(opt);
      });
    }

    // ── Wire up date inputs ──────────────────────────────────────────────────
    document.getElementById('dateFrom').addEventListener('change', () => { highlightBtn(''); applyFilter(); });
    document.getElementById('dateTo').addEventListener('change',   () => { highlightBtn(''); applyFilter(); });

    // ── Init ─────────────────────────────────────────────────────────────────
    populateJobFilter();
    // Default: last 7 days (or all data if we have fewer)
    const initDays = Math.min(7, embeddedDays);
    setRange(initDays);

    // ── Failure Details ──────────────────────────────────────────────────────
    function renderFailureDetails(rows) {
      const failedRows = rows.filter(r =>
        (r.failedTitles && r.failedTitles.length > 0) ||
        (r.flakyTitles  && r.flakyTitles.length  > 0)
      );
      const analysisEl = document.getElementById('analysisSection');

      if (failedRows.length === 0) {
        analysisEl.innerHTML = '';
        return;
      }

      let aHtml = `
        <div class="mb-4">
          <h2 class="text-xl font-bold text-gray-800 flex items-center gap-2">
            <span>🔍</span> Failure Details
            <span class="text-sm font-normal text-gray-500">(${failedRows.length} build${failedRows.length !== 1 ? 's' : ''} with failures in selected range)</span>
          </h2>
        </div>`;

      failedRows.forEach(r => {
        const shortJob    = r.jobName.replace('wpa-wmt-', '');
        const totalFailed = (r.failedTitles || []).length;
        const totalFlaky  = (r.flakyTitles  || []).length;
        const ranAt       = r.startTime ? new Date(r.startTime).toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : '';

        aHtml += `
        <div class="mb-6 rounded-lg border border-red-200 shadow-sm overflow-hidden">
          <button onclick="this.nextElementSibling.classList.toggle('hidden'); this.querySelector('.chevron').classList.toggle('rotate-90')"
                  class="w-full bg-red-50 px-5 py-3 flex items-center justify-between text-left hover:bg-red-100 transition-colors"
                  aria-expanded="false">
            <div class="flex items-center gap-3">
              <span class="status-dot dot-fail"></span>
              <div>
                <span class="font-semibold text-gray-800">${shortJob}</span>
                <span class="text-gray-500 mx-1">→</span>
                <span class="font-mono text-sm text-gray-700">${r.flowName}</span>
                <span class="text-xs text-gray-400 ml-2">#${r.buildNumber}</span>
                ${ranAt ? `<span class="text-xs text-gray-400 ml-1">· ${ranAt}</span>` : ''}
              </div>
            </div>
            <div class="flex items-center gap-3">
              ${totalFailed ? `<span class="text-xs px-2 py-0.5 rounded-full status-fail">${totalFailed} failed</span>` : ''}
              ${totalFlaky  ? `<span class="text-xs px-2 py-0.5 rounded-full status-cancelled">${totalFlaky} flaky</span>` : ''}
              <svg class="chevron w-4 h-4 text-gray-400 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
              </svg>
            </div>
          </button>
          <div class="hidden bg-white divide-y divide-gray-50">`;

        if (r.failedTitles && r.failedTitles.length) {
          aHtml += `<div class="px-5 py-3"><p class="text-xs font-semibold text-red-600 uppercase tracking-wide mb-2">❌ Failed Tests (${r.failedTitles.length})</p><ul class="space-y-1">`;
          r.failedTitles.forEach(t => {
            const safe = t.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
            aHtml += `<li class="text-sm text-gray-700 font-mono bg-red-50 rounded px-2 py-1">❌ ${safe}</li>`;
          });
          aHtml += '</ul></div>';
        }

        if (r.flakyTitles && r.flakyTitles.length) {
          aHtml += `<div class="px-5 py-3"><p class="text-xs font-semibold text-yellow-700 uppercase tracking-wide mb-2">🎲 Flaky Tests (${r.flakyTitles.length})</p><ul class="space-y-1">`;
          r.flakyTitles.forEach(t => {
            const safe = t.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
            aHtml += `<li class="text-sm text-gray-700 font-mono bg-yellow-50 rounded px-2 py-1">🎲 ${safe}</li>`;
          });
          aHtml += '</ul></div>';
        }

        aHtml += `
            <div class="border-t border-gray-100 px-5 py-2 bg-gray-50 text-right">
              <a href="${r.reportUrl}" target="_blank" rel="noopener"
                 class="text-[#0053e2] hover:text-[#003d9e] text-xs underline">View Full Report →</a>
            </div>
          </div>
        </div>`;
      });

      analysisEl.innerHTML = aHtml;
    }

    // ── AI Analysis ───────────────────────────────────────────────────────────
    const aiEl = document.getElementById('aiAnalysisSection');
    const rowByFlow = {};
    allRows.forEach(r => { if (!rowByFlow[r.flowName]) rowByFlow[r.flowName] = r; });

    if (aiAnalysis && aiAnalysis.length > 0) {
      const sevIcon     = { high: '🔴', medium: '🟡', low: '🟢' };
      const sevLabel    = { high: 'High', medium: 'Medium', low: 'Low' };
      const sevBorder   = { high: 'border-[#ea1100]', medium: 'border-[#ffc220]', low: 'border-[#2a8703]' };
      const sevBg       = { high: 'bg-red-50', medium: 'bg-yellow-50', low: 'bg-green-50' };
      const sevHeaderBg = { high: 'bg-red-100', medium: 'bg-yellow-100', low: 'bg-green-100' };
      const classIcon   = { service_regression: '🔧', environment_issue: '🌐', test_issue: '🧪', flaky: '🎲' };
      const classBadgeBg = {
        service_regression: 'bg-red-100 text-[#ea1100]',
        environment_issue:  'bg-blue-100 text-[#0053e2]',
        test_issue:         'bg-yellow-100 text-[#995213]',
        flaky:              'bg-gray-100 text-gray-600',
      };

      const sevOrder = { high: 0, medium: 1, low: 2 };
      const sorted = [...aiAnalysis].sort((a, b) => (sevOrder[a.severity] ?? 9) - (sevOrder[b.severity] ?? 9));
      const highN = sorted.filter(a => a.severity === 'high').length;
      const medN  = sorted.filter(a => a.severity === 'medium').length;
      const lowN  = sorted.filter(a => a.severity === 'low').length;

      let aiHtml = `
        <div class="mb-4 flex flex-wrap items-center gap-4 justify-between">
          <div>
            <h2 class="text-xl font-bold text-gray-800 flex items-center gap-2">
              🐶 AI Failure Analysis
              <span class="text-sm font-normal text-gray-500">${sorted.length} flow${sorted.length !== 1 ? 's' : ''} · via playwright-monocart-helper</span>
            </h2>
            <p class="text-sm text-gray-500 mt-1">Root-cause classification &amp; recommendations powered by Code Puppy</p>
          </div>
          <div class="flex gap-2 text-xs">
            ${highN ? `<span class="bg-red-100 text-[#ea1100] px-2 py-1 rounded-full font-semibold">🔴 ${highN} High</span>` : ''}
            ${medN  ? `<span class="bg-yellow-100 text-[#995213] px-2 py-1 rounded-full font-semibold">🟡 ${medN} Medium</span>` : ''}
            ${lowN  ? `<span class="bg-green-100 text-[#2a8703] px-2 py-1 rounded-full font-semibold">🟢 ${lowN} Low</span>` : ''}
          </div>
        </div>
        <div class="grid grid-cols-1 lg:grid-cols-2 gap-4 mb-6">`;

      sorted.forEach(a => {
        const sev      = a.severity || 'medium';
        const cls      = a.classification || 'unknown';
        const border   = sevBorder[sev]   || 'border-gray-300';
        const bg       = sevBg[sev]       || 'bg-gray-50';
        const headerBg = sevHeaderBg[sev] || 'bg-gray-100';
        const cIcon    = classIcon[cls]   || '❓';
        const cBadge   = classBadgeBg[cls]|| 'bg-gray-100 text-gray-700';
        const clsLabel = cls.replace(/_/g, ' ');
        const sevLbl   = sevLabel[sev]    || sev;
        const row      = rowByFlow[a.flow] || {};
        const reportUrl= row.reportUrl || '';
        const jobShort = (a.job || row.jobName || '').replace('wpa-wmt-', '');

        aiHtml += `
          <div class="${bg} rounded-lg border ${border} shadow-sm overflow-hidden">
            <div class="${headerBg} px-4 py-2 flex items-center justify-between">
              <div class="flex items-center gap-2 min-w-0">
                <span class="text-base flex-shrink-0">${sevIcon[sev] || '⚪'}</span>
                <div class="min-w-0">
                  <p class="font-semibold text-gray-800 truncate text-sm" title="${a.flow}">${a.flow}</p>
                  ${jobShort ? `<p class="text-xs text-gray-500 truncate">${jobShort}</p>` : ''}
                </div>
              </div>
              <div class="flex items-center gap-2 flex-shrink-0 ml-2">
                <span class="inline-flex items-center gap-1 text-xs px-2 py-0.5 rounded-full ${cBadge} whitespace-nowrap">
                  ${cIcon} ${clsLabel}
                </span>
                ${reportUrl ? `<a href="${reportUrl}" target="_blank" rel="noopener"
                     class="text-[#0053e2] hover:text-[#003d9e] text-xs underline whitespace-nowrap">Report →</a>` : ''}
              </div>
            </div>
            <div class="px-4 py-3">
              <p class="text-sm text-gray-700 leading-relaxed">${a.summary}</p>
              <div class="mt-3 border-t border-white border-opacity-60 pt-3">
                <p class="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1">💡 Recommendation</p>
                <p class="text-sm text-gray-600 leading-relaxed">${a.recommendation}</p>
              </div>
            </div>
          </div>`;
      });

      aiHtml += '</div>';
      aiEl.innerHTML = aiHtml;

    } else {
      const hasFailures = allRows.some(r => r.buildStatus === 'FAILURE');
      if (hasFailures) {
        aiEl.innerHTML = `
          <div class="bg-blue-50 border border-[#0053e2] border-opacity-20 rounded-lg px-5 py-4 flex items-start gap-3">
            <span class="text-2xl">🐶</span>
            <div>
              <p class="font-semibold text-[#0053e2] text-sm">AI Failure Analysis available</p>
              <p class="text-sm text-gray-600 mt-1">
                Re-run with <code class="bg-white px-1 py-0.5 rounded border border-gray-200 text-xs font-mono">python3 tools/daily_dashboard.py --ai --open</code>
                to get root-cause classification and recommendations from
                <strong>playwright-monocart-helper</strong>.
              </p>
            </div>
          </div>`;
      }
    }
  </script>

  <footer class="text-center text-xs text-gray-400 py-4">
    Generated by Code Puppy 🐶 | Playwright Monocart Helper 🎭
  </footer>
</body>
</html>
