import { buildNavbar } from './portal-navbar.js';
import { getPortalThemeCSS } from './portal-theme.js';
function escapeHtml(s) {
    return s
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;');
}
function formatDate(dateStr) {
    try {
        const d = new Date(dateStr);
        return d.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });
    }
    catch {
        return escapeHtml(dateStr);
    }
}
function getYearMonth(dateStr) {
    try {
        const d = new Date(dateStr);
        return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`;
    }
    catch {
        return 'unknown';
    }
}
function accuracyClass(estimated, actual) {
    if (estimated <= 0) {
        return { label: 'N/A', cls: 'planu-badge-muted' };
    }
    const ratio = Math.abs(actual - estimated) / estimated;
    if (ratio <= 0.2) {
        return { label: `±${Math.round(ratio * 100)}%`, cls: 'planu-badge-success' };
    }
    if (ratio <= 0.5) {
        return { label: `±${Math.round(ratio * 100)}%`, cls: 'planu-badge-warning' };
    }
    return { label: `±${Math.round(ratio * 100)}%`, cls: 'planu-badge-danger' };
}
function buildSpecCard(spec) {
    const completedAt = spec.actuals?.completedAt ?? '';
    const dateDisplay = completedAt ? formatDate(completedAt) : 'Unknown date';
    const estimatedHours = spec.estimation.devHours + spec.estimation.reviewHours;
    const actualHours = spec.actuals ? spec.actuals.devHours + spec.actuals.reviewHours : 0;
    const { label: accLabel, cls: accCls } = accuracyClass(estimatedHours, actualHours);
    const actualDisplay = spec.actuals !== null
        ? `<span class="hours-actual">${actualHours.toFixed(1)}h actual</span>`
        : '';
    const tagBadges = spec.tags.length > 0
        ? spec.tags
            .slice(0, 3)
            .map((t) => `<span class="tag-chip">${escapeHtml(t)}</span>`)
            .join('')
        : '';
    return `<div class="cl-card planu-card">
    <div class="cl-header">
      <span class="cl-id">${escapeHtml(spec.id)}</span>
      <span class="cl-title">${escapeHtml(spec.title)}</span>
      <span class="planu-badge ${accCls}">${accLabel}</span>
      <span class="cl-date">${dateDisplay}</span>
    </div>
    <div class="cl-meta">
      <span class="hours-est">${estimatedHours.toFixed(1)}h est</span>
      ${actualDisplay}
      ${tagBadges}
    </div>
  </div>`;
}
function buildFeed(doneSpecs) {
    if (doneSpecs.length === 0) {
        return '';
    }
    // Group by year-month
    const groups = new Map();
    for (const spec of doneSpecs) {
        const key = spec.actuals?.completedAt ? getYearMonth(spec.actuals.completedAt) : 'unknown';
        const arr = groups.get(key) ?? [];
        arr.push(spec);
        groups.set(key, arr);
    }
    // Sort keys descending
    const sortedKeys = [...groups.keys()].sort((a, b) => b.localeCompare(a));
    return sortedKeys
        .map((key) => {
        const specs = groups.get(key) ?? [];
        const label = key === 'unknown' ? 'Unknown Date' : key;
        const cards = specs.map(buildSpecCard).join('\n');
        return `<div class="month-group">
        <div class="month-header">${escapeHtml(label)}</div>
        ${cards}
      </div>`;
    })
        .join('\n');
}
function buildSummarySection(doneSpecs) {
    if (doneSpecs.length === 0) {
        return '';
    }
    const now = new Date();
    const currentMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
    const thisMonth = doneSpecs.filter((s) => s.actuals?.completedAt && getYearMonth(s.actuals.completedAt) === currentMonth);
    const totalHours = doneSpecs.reduce((sum, s) => {
        if (!s.actuals) {
            return sum;
        }
        return sum + s.actuals.devHours + s.actuals.reviewHours;
    }, 0);
    const specsWithActuals = doneSpecs.filter((s) => s.actuals !== null && s.estimation.devHours > 0);
    const avgAccuracy = specsWithActuals.length > 0
        ? specsWithActuals.reduce((sum, s) => {
            const est = s.estimation.devHours + s.estimation.reviewHours;
            const act = (s.actuals?.devHours ?? 0) + (s.actuals?.reviewHours ?? 0);
            return sum + Math.abs(act - est) / est;
        }, 0) / specsWithActuals.length
        : null;
    const accDisplay = avgAccuracy !== null ? `${Math.round(avgAccuracy * 100)}%` : 'N/A';
    return `<section class="planu-card section-card summary-section">
    <h2>Summary</h2>
    <div class="summary-grid">
      <div class="sum-item">
        <span class="sum-num">${doneSpecs.length}</span>
        <span class="sum-lbl">Total Done</span>
      </div>
      <div class="sum-item">
        <span class="sum-num">${thisMonth.length}</span>
        <span class="sum-lbl">This Month</span>
      </div>
      <div class="sum-item">
        <span class="sum-num">${totalHours.toFixed(0)}h</span>
        <span class="sum-lbl">Total Hours</span>
      </div>
      <div class="sum-item">
        <span class="sum-num">${accDisplay}</span>
        <span class="sum-lbl">Avg Deviation</span>
      </div>
    </div>
  </section>`;
}
function buildPageCSS() {
    return `
  body { font-family: system-ui, sans-serif; margin: 0; padding: 0 16px 48px; background: var(--planu-bg); color: var(--planu-text); }
  .page-title { font-size: 1.6rem; font-weight: 700; margin: 0 0 6px; }
  .page-subtitle { color: #6b7280; margin: 0 0 24px; font-size: 0.95rem; }
  .section-card { margin-bottom: 24px; }
  h2 { font-size: 1.1rem; font-weight: 600; margin: 0 0 16px; color: var(--planu-primary); }
  .summary-grid { display: flex; gap: 16px; flex-wrap: wrap; }
  .sum-item { text-align: center; padding: 12px 20px; background: #f9fafb; border-radius: 8px; min-width: 80px; }
  .sum-num { display: block; font-size: 1.8rem; font-weight: 700; color: var(--planu-primary); }
  .sum-lbl { font-size: 0.78rem; color: #6b7280; }
  .month-group { margin-bottom: 24px; }
  .month-header { font-size: 0.85rem; font-weight: 700; color: #9ca3af; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 10px; padding-left: 4px; }
  .cl-card { margin-bottom: 10px; padding: 12px 14px; }
  .cl-header { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 4px; }
  .cl-id { font-weight: 700; color: #6b7280; font-size: 0.82rem; }
  .cl-title { font-weight: 600; flex: 1; }
  .cl-date { font-size: 0.78rem; color: #9ca3af; margin-left: auto; }
  .cl-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 0.78rem; }
  .hours-est { color: #6b7280; }
  .hours-actual { color: var(--planu-primary); font-weight: 600; }
  .tag-chip { padding: 2px 6px; border-radius: 4px; background: #f3f4f6; color: #374151; }
  .empty-state { text-align: center; padding: 64px 24px; color: #6b7280; }
  .empty-state h3 { font-size: 1.2rem; }`;
}
/**
 * Generate the changelog.html portal page.
 */
export function generateChangelogPage(specs) {
    const doneSpecs = specs
        .filter((s) => s.status === 'done')
        .sort((a, b) => {
        const aDate = a.actuals?.completedAt ?? '';
        const bDate = b.actuals?.completedAt ?? '';
        return bDate.localeCompare(aDate);
    });
    const navbar = buildNavbar('changelog', '');
    const themeCSS = getPortalThemeCSS();
    const pageCSS = buildPageCSS();
    const bodyContent = doneSpecs.length === 0
        ? `<div class="empty-state"><h3>No completed specs yet.</h3><p>Specs marked as <code>done</code> will appear here.</p></div>`
        : `${buildSummarySection(doneSpecs)}
  <section class="section-card">
    <h2>Completion Feed</h2>
    ${buildFeed(doneSpecs)}
  </section>`;
    return `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Changelog — Planu Portal</title>
  <style>${themeCSS}${pageCSS}</style>
</head>
<body>
  ${navbar}
  <main>
    <h1 class="page-title">📝 Changelog</h1>
    <p class="page-subtitle">Completed specs in reverse chronological order with estimation accuracy.</p>
    ${bodyContent}
  </main>
</body>
</html>`;
}
//# sourceMappingURL=changelog-page.js.map