/*
 * Copyright 2026, Jaime Terrats.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { summarizeEffort } from '../services/workflow-effort.js';
function computeEffort(runs, doneTasks) {
    let aiSupervisedMs = 0;
    let aiAutonomousMs = 0;
    for (const run of runs) {
        for (const phase of run.phases) {
            if (phase.status === 'done' && phase.completedAt) {
                const dur = new Date(phase.completedAt).getTime() - new Date(phase.startedAt).getTime();
                if (run.gates === 'none')
                    aiAutonomousMs += dur;
                else
                    aiSupervisedMs += dur;
            }
        }
    }
    const aiSupervisedHours = hoursFromMs(aiSupervisedMs);
    const aiAutonomousHours = hoursFromMs(aiAutonomousMs);
    const manualHours = doneTasks > 0 ? Math.max(0, doneTasks * 0.5 - aiSupervisedHours - aiAutonomousHours) : 0;
    const totalHours = Math.round((manualHours + aiSupervisedHours + aiAutonomousHours) * 10) / 10;
    const aiRatioPct = totalHours > 0 ? Math.round(((aiSupervisedHours + aiAutonomousHours) / totalHours) * 100) : 0;
    return { manualHours, aiSupervisedHours, aiAutonomousHours, totalHours, aiRatioPct };
}
function computeEffortFromSizing() {
    return { manualHours: 0, aiSupervisedHours: 0, aiAutonomousHours: 0, totalHours: 0, aiRatioPct: 0 };
}
function dayKey(iso) {
    return iso.slice(0, 10);
}
function hoursFromMs(ms) {
    return Math.round((ms / 3_600_000) * 10) / 10;
}
function tallyTasks(active) {
    const taskCounts = { total: active.length, done: 0, claimed: 0, open: 0, cancelled: 0 };
    const velocity = {};
    const byProfile = {};
    for (const t of active) {
        if (t.status === 'done')
            taskCounts.done++;
        else if (t.status === 'claimed')
            taskCounts.claimed++;
        else if (t.status === 'cancelled')
            taskCounts.cancelled++;
        else
            taskCounts.open++;
        const profile = t.owner ? t.owner.replace('setup-agents:', '') : 'unknown';
        if (!byProfile[profile])
            byProfile[profile] = { total: 0, done: 0 };
        byProfile[profile].total++;
        if (t.status === 'done') {
            byProfile[profile].done++;
            const day = dayKey(t.updatedAt);
            velocity[day] = (velocity[day] ?? 0) + 1;
        }
    }
    return { taskCounts, velocity, byProfile };
}
function computeCycleTimes(doneRuns) {
    const storyCycleTimes = {};
    const phaseMs = {};
    for (const run of doneRuns) {
        const runStartMs = new Date(run.createdAt).getTime();
        const runEndMs = new Date(run.updatedAt).getTime();
        storyCycleTimes[run.storyId] = hoursFromMs(runEndMs - runStartMs);
        for (const phase of run.phases) {
            if (phase.status === 'done' && phase.completedAt) {
                const dur = new Date(phase.completedAt).getTime() - new Date(phase.startedAt).getTime();
                if (!phaseMs[phase.phase])
                    phaseMs[phase.phase] = [];
                phaseMs[phase.phase].push(dur);
            }
        }
    }
    const phaseCycleTimes = {};
    for (const [phase, durations] of Object.entries(phaseMs)) {
        const avg = durations.reduce((a, b) => a + b, 0) / durations.length;
        phaseCycleTimes[phase] = hoursFromMs(avg);
    }
    return { storyCycleTimes, phaseCycleTimes };
}
function buildRecentHandoffs(handoffs) {
    handoffs.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
    return handoffs.slice(0, 10).map((h) => ({
        id: h.id,
        from: h.from?.replace('setup-agents:', '') ?? 'unknown',
        to: h.to?.replace('setup-agents:', '') ?? 'unknown',
        summary: h.summary.length > 80 ? h.summary.slice(0, 77) + '...' : h.summary,
        createdAt: h.createdAt,
        taskId: h.taskIds[0] ?? null,
    }));
}
// ─── Main metrics computation ────────────────────────────────────────────────
export function computeMetrics(tasks, runs, projectName, effortRecords = [], handoffs = [], sizingEstimates = []) {
    const active = tasks.filter((t) => !['deleted', 'archived'].includes(t.status));
    const { taskCounts, velocity, byProfile } = tallyTasks(active);
    const doneRuns = runs.filter((r) => r.status === 'done');
    const { storyCycleTimes, phaseCycleTimes } = computeCycleTimes(doneRuns);
    const hasRuntimeEffort = runs.length > 0 || effortRecords.length > 0;
    const effort = hasRuntimeEffort ? computeEffort(runs, taskCounts.done) : computeEffortFromSizing();
    const tokenCost = effortRecords.length > 0 ? summarizeEffort(effortRecords, null).tokenCost : null;
    const recentHandoffs = buildRecentHandoffs(handoffs);
    const sizingEstimate = sizingEstimates.length > 0
        ? {
            totalSoloDays: sizingEstimates.reduce((s, e) => s + e.soloEstimateDays, 0),
            totalAiUnguidedDays: sizingEstimates.reduce((s, e) => s + e.aiUnguidedEstimateDays, 0),
            storiesEstimated: sizingEstimates.length,
        }
        : null;
    return {
        generatedAt: new Date().toISOString(),
        projectName,
        tasks: taskCounts,
        effort,
        sizingEstimate,
        tokenCost,
        velocity,
        byProfile,
        storyCycleTimes,
        phaseCycleTimes,
        recentHandoffs,
        sizingEstimateDetails: sizingEstimates,
    };
}
export function generateDashboardHtml(metrics) {
    const { tasks, effort, velocity, byProfile, storyCycleTimes, phaseCycleTimes, generatedAt, projectName, sizingEstimateDetails, } = metrics;
    const completionPct = tasks.total > 0 ? Math.round((tasks.done / tasks.total) * 100) : 0;
    const velocityLabels = Object.keys(velocity).sort((a, b) => a.localeCompare(b));
    const velocityData = velocityLabels.map((d) => velocity[d]);
    // Burndown: cumulative done by day
    const allDays = velocityLabels;
    let cumDone = 0;
    const burndownDone = allDays.map((d) => {
        cumDone += velocity[d] ?? 0;
        return cumDone;
    });
    const burndownRemaining = allDays.map((_, i) => tasks.total - burndownDone[i]);
    const profileLabels = Object.keys(byProfile).sort((a, b) => byProfile[b].total - byProfile[a].total);
    const profileTotals = profileLabels.map((p) => byProfile[p].total);
    const profileDone = profileLabels.map((p) => byProfile[p].done);
    const storyLabels = Object.keys(storyCycleTimes)
        .sort((a, b) => storyCycleTimes[b] - storyCycleTimes[a])
        .slice(0, 15);
    const storyData = storyLabels.map((s) => storyCycleTimes[s]);
    const phaseLabels = Object.keys(phaseCycleTimes).sort((a, b) => a.localeCompare(b));
    const phaseData = phaseLabels.map((p) => phaseCycleTimes[p]);
    const benchmarkRows = sizingEstimateDetails.map((est) => {
        const actualHours = storyCycleTimes[est.storyId] ?? null;
        const actualDays = actualHours !== null ? Math.round((actualHours / 8) * 1000) / 1000 : null;
        const savingsVsSolo = actualDays !== null && est.soloEstimateDays > 0
            ? Math.round(((est.soloEstimateDays - actualDays) / est.soloEstimateDays) * 100)
            : null;
        const savingsVsUnguided = actualDays !== null && est.aiUnguidedEstimateDays > 0
            ? Math.round(((est.aiUnguidedEstimateDays - actualDays) / est.aiUnguidedEstimateDays) * 100)
            : null;
        return {
            storyId: est.storyId,
            sizing: est.sizingLabel,
            soloDays: est.soloEstimateDays,
            aiUnguidedDays: est.aiUnguidedEstimateDays,
            aiGuidedDays: est.aiGuidedDays ?? null,
            actualDays,
            savingsVsSolo,
            savingsVsUnguided,
        };
    });
    const benchWithActuals = benchmarkRows.filter((r) => r.actualDays !== null);
    const formattedDate = new Date(generatedAt).toLocaleString('es-MX', {
        year: 'numeric',
        month: 'short',
        day: 'numeric',
        hour: '2-digit',
        minute: '2-digit',
    });
    return `<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>${escHtml(projectName)} — Delivery Dashboard</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.3/dist/chart.umd.min.js"></script>
<style>
  :root {
    --slds-blue:#0176d3;--slds-blue-light:#e3effc;
    --slds-green:#2e844a;--slds-green-light:#e3f5e1;
    --slds-orange:#dd7a01;--slds-orange-light:#fef1e2;
    --slds-red:#c23934;--slds-gray:#706e6b;--slds-bg:#f3f2f2;
    --slds-white:#fff;--slds-border:#dddbda;
  }
  *{box-sizing:border-box;margin:0;padding:0}
  body{font-family:'Salesforce Sans',Arial,sans-serif;background:var(--slds-bg);color:#3e3e3c;font-size:14px}
  header{background:var(--slds-blue);color:#fff;padding:16px 24px;display:flex;align-items:center;justify-content:space-between}
  header h1{font-size:20px;font-weight:600}
  header span{font-size:12px;opacity:.85}
  .grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px;padding:20px 24px}
  .grid-wide{display:grid;grid-template-columns:1fr 1fr;gap:16px;padding:0 24px 20px}
  .grid-full{padding:0 24px 20px}
  .card{background:var(--slds-white);border:1px solid var(--slds-border);border-radius:8px;padding:16px}
  .card h2{font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--slds-gray);margin-bottom:12px}
  .kpi{font-size:36px;font-weight:700;color:var(--slds-blue)}
  .kpi-sub{font-size:13px;color:var(--slds-gray);margin-top:2px}
  .progress-bar{height:8px;background:var(--slds-border);border-radius:4px;overflow:hidden;margin-top:8px}
  .progress-fill{height:100%;background:var(--slds-blue);border-radius:4px}
  canvas{max-height:260px}
  table{width:100%;border-collapse:collapse;font-size:13px}
  th{text-align:left;padding:6px 8px;background:var(--slds-bg);font-weight:600;border-bottom:2px solid var(--slds-border)}
  td{padding:6px 8px;border-bottom:1px solid var(--slds-border)}
  .tag{display:inline-block;padding:2px 8px;border-radius:12px;font-size:11px;font-weight:600}
  .tag-blue{background:var(--slds-blue-light);color:var(--slds-blue)}
  .tag-green{background:var(--slds-green-light);color:var(--slds-green)}
  .tag-orange{background:var(--slds-orange-light);color:var(--slds-orange)}
  footer{text-align:center;padding:16px;font-size:11px;color:var(--slds-gray)}
  .note{font-size:11px;color:var(--slds-gray);margin-top:8px;padding:8px 12px;background:var(--slds-bg);border-radius:4px;border-left:3px solid var(--slds-blue)}
  .savings-pos{color:var(--slds-green);font-weight:600}
  .savings-neg{color:var(--slds-red);font-weight:600}
  .no-data{color:var(--slds-gray);font-style:italic}
  @media(max-width:700px){.grid-wide{grid-template-columns:1fr}}
</style>
</head>
<body>
<header>
  <h1>${escHtml(projectName)} — Delivery Dashboard</h1>
  <span>Generated ${escHtml(formattedDate)}</span>
</header>

<!-- KPI row -->
<div class="grid">
  <div class="card">
    <h2>Tasks completed</h2>
    <div class="kpi">${tasks.done}</div>
    <div class="kpi-sub">${completionPct}% of ${tasks.total} tasks</div>
    <div class="progress-bar"><div class="progress-fill" style="width:${completionPct}%"></div></div>
  </div>
  <div class="card">
    <h2>Sprint status</h2>
    <div style="display:flex;flex-wrap:wrap;gap:12px;margin-top:4px">
      <span class="tag tag-green">✓ ${tasks.done} done</span>
      <span class="tag tag-blue">⚡ ${tasks.claimed} active</span>
      <span class="tag tag-orange">○ ${tasks.open} open</span>
      ${tasks.cancelled > 0
        ? `<span class="tag" style="background:#f3f2f2;color:#706e6b">✗ ${tasks.cancelled} cancelled</span>`
        : ''}
    </div>
    <canvas id="statusDonut" style="max-height:160px;margin-top:12px"></canvas>
  </div>
  <div class="card">
    <h2>Actual effort</h2>
    ${effort.totalHours > 0
        ? `<div class="kpi">${effort.totalHours}h</div>
    <div class="kpi-sub">AI ratio: ${effort.aiRatioPct}%</div>
    <canvas id="effortDonut" style="max-height:160px;margin-top:12px"></canvas>
    <p class="note">Effort calculated from workflow-runs.jsonl phase durations. AI Autonomous = phases with gates=none. AI Supervised = phases with gate checks.</p>`
        : `<div class="kpi" style="font-size:18px;color:var(--slds-gray)">No runtime data</div>
    <div class="kpi-sub">Add effort records via workflow phases</div>`}
  </div>
  ${effort.totalHours > 0
        ? `<div class="card">
    <h2>Effort by mode</h2>
    <table>
      <tr><th>Mode</th><th>Hours</th></tr>
      <tr><td>Solo / Manual</td><td>${effort.manualHours}h</td></tr>
      <tr><td>AI Supervised</td><td>${effort.aiSupervisedHours}h</td></tr>
      <tr><td>AI Autonomous</td><td>${effort.aiAutonomousHours}h</td></tr>
    </table>
  </div>`
        : ''}
${metrics.tokenCost
        ? `
  <div class="card">
    <h2>Estimated AI cost (USD)</h2>
    <div class="kpi">$${metrics.tokenCost.totalCostUsd.toFixed(4)}</div>
    <div class="kpi-sub">${Object.values(metrics.tokenCost.byMode).reduce((s, e) => s + e.phases, 0)} phases with cost recorded</div>
    <canvas id="tokenCostDonut" style="max-height:160px;margin-top:12px"></canvas>
  </div>`
        : ''}
${metrics.sizingEstimate
        ? `
  <div class="card">
    <h2>Sizing estimates</h2>
    <table>
      <tr><th>Metric</th><th>Value</th></tr>
      <tr><td>Stories estimated</td><td>${metrics.sizingEstimate.storiesEstimated}</td></tr>
      <tr><td>Solo estimate (days)</td><td>${metrics.sizingEstimate.totalSoloDays}</td></tr>
      <tr><td>AI-unguided estimate (days)</td><td>${metrics.sizingEstimate.totalAiUnguidedDays}</td></tr>
      <tr><td>AI savings ratio</td><td>${Math.round((1 - metrics.sizingEstimate.totalAiUnguidedDays / metrics.sizingEstimate.totalSoloDays) * 100)}%</td></tr>
    </table>
  </div>`
        : ''}
</div>

<!-- Charts row 1 -->
<div class="grid-wide">
  <div class="card">
    <h2>Burndown</h2>
    <canvas id="burndown"></canvas>
  </div>
  <div class="card">
    <h2>Daily velocity (tasks closed)</h2>
    <canvas id="velocity"></canvas>
  </div>
</div>

<!-- Charts row 2 -->
<div class="grid-wide">
  <div class="card">
    <h2>Tasks by profile</h2>
    <canvas id="byProfile"></canvas>
  </div>
  <div class="card">
    <h2>Avg cycle time by phase (h)</h2>
    <canvas id="phaseTime"></canvas>
  </div>
</div>

<!-- Story cycle times -->
${storyLabels.length > 0
        ? `
<div class="grid-full">
  <div class="card">
    <h2>Cycle time by story (h)</h2>
    <canvas id="storyCycle" style="max-height:220px"></canvas>
  </div>
</div>`
        : ''}

<!-- Profile table -->
${profileLabels.length > 0
        ? `
<div class="grid-full">
  <div class="card">
    <h2>Profile distribution</h2>
    <table>
      <tr><th>Profile</th><th>Total</th><th>Done</th><th>Completion</th></tr>
      ${profileLabels
            .map((p) => {
            const pct = byProfile[p].total > 0 ? Math.round((byProfile[p].done / byProfile[p].total) * 100) : 0;
            return `<tr><td>${escHtml(p)}</td><td>${byProfile[p].total}</td><td>${byProfile[p].done}</td><td>
          <div class="progress-bar"><div class="progress-fill" style="width:${pct}%"></div></div>
          ${pct}%
        </td></tr>`;
        })
            .join('')}
    </table>
  </div>
</div>`
        : ''}

${benchmarkRows.length > 0
        ? `
<div class="grid-full">
  <div class="card">
    <h2>Story benchmark detail</h2>
    <table>
      <tr><th>Story</th><th>Sizing</th><th>Solo Est.</th><th>AI Unguided Est.</th><th>AI Guided Est.</th><th>Actual</th><th>Savings vs Solo</th><th>Savings vs Unguided</th></tr>
      ${benchmarkRows
            .map((r) => {
            const actualCell = r.actualDays !== null ? `${r.actualDays}d` : '<span class="no-data">no run data</span>';
            const savSoloCell = r.savingsVsSolo !== null
                ? `<span class="${r.savingsVsSolo >= 0 ? 'savings-pos' : 'savings-neg'}">${r.savingsVsSolo}%</span>`
                : '<span class="no-data">—</span>';
            const savUngCell = r.savingsVsUnguided !== null
                ? `<span class="${r.savingsVsUnguided >= 0 ? 'savings-pos' : 'savings-neg'}">${r.savingsVsUnguided}%</span>`
                : '<span class="no-data">—</span>';
            return `<tr><td>${escHtml(r.storyId)}</td><td>${escHtml(r.sizing)}</td><td>${r.soloDays}d</td><td>${r.aiUnguidedDays}d</td><td>${r.aiGuidedDays !== null ? r.aiGuidedDays + 'd' : '—'}</td><td>${actualCell}</td><td>${savSoloCell}</td><td>${savUngCell}</td></tr>`;
        })
            .join('')}
    </table>
    <p class="note">Actual = wall-clock time from workflow-runs.jsonl. Estimates declared via \`sf setup-agents workflow estimate\`.</p>
  </div>
</div>`
        : ''}

${benchWithActuals.length > 0
        ? `
<div class="grid-wide">
  <div class="card">
    <h2>Actual vs Estimates (days) — ${benchWithActuals.length} stories with run data</h2>
    <canvas id="benchmarkBar"></canvas>
  </div>
  <div class="card">
    <h2>Savings % vs Solo — by story</h2>
    <canvas id="savingsBar"></canvas>
  </div>
</div>
<div class="grid-full" style="padding-top:0">
  <p class="note">Solo estimate = days a developer would take without AI. AI Guided = with AI + human review. Actual = wall-clock from workflow telemetry.</p>
</div>`
        : ''}

${metrics.recentHandoffs.length > 0
        ? `
<div class="grid-full">
  <div class="card">
    <h2>Recent Handoffs</h2>
    <table>
      <tr><th>From</th><th>To</th><th>Summary</th><th>Task</th><th>Date</th></tr>
      ${metrics.recentHandoffs
            .map((h) => `<tr><td>${escHtml(h.from)}</td><td>${escHtml(h.to)}</td><td title="${escHtml(h.summary)}">${escHtml(h.summary)}</td><td>${escHtml(h.taskId ?? '—')}</td><td>${h.createdAt.slice(0, 10)}</td></tr>`)
            .join('')}
    </table>
  </div>
</div>`
        : ''}

<footer>
  setup-agents delivery dashboard · source: .setup-agents/state/ · ${escHtml(formattedDate)}
</footer>

<script>
const SLDS = {
  blue:'#0176d3', blueLight:'#e3effc',
  green:'#2e844a', greenLight:'#e3f5e1',
  orange:'#dd7a01', orangeLight:'#fef1e2',
  red:'#c23934', gray:'#706e6b',
  teal:'#0d9dda', purple:'#9050e9',
};

${metrics.tokenCost
        ? `new Chart(document.getElementById('tokenCostDonut'),{type:'doughnut',data:{
  labels:${JSON.stringify(Object.keys(metrics.tokenCost.byMode))},
  datasets:[{data:${JSON.stringify(Object.values(metrics.tokenCost.byMode).map((e) => e.costUsd))},
    backgroundColor:[SLDS.blue,SLDS.teal,SLDS.purple,SLDS.gray,SLDS.orange],borderWidth:0}]
},options:{plugins:{legend:{position:'bottom'}},cutout:'65%'}});`
        : ''}

new Chart(document.getElementById('statusDonut'),{type:'doughnut',data:{
  labels:['Done','Active','Open'${tasks.cancelled > 0 ? ",'Cancelled'" : ''}],
  datasets:[{data:[${tasks.done},${tasks.claimed},${tasks.open}${tasks.cancelled > 0 ? `,${tasks.cancelled}` : ''}],
    backgroundColor:[SLDS.green,SLDS.blue,SLDS.orange${tasks.cancelled > 0 ? ',SLDS.gray' : ''}],borderWidth:0}]
},options:{plugins:{legend:{position:'bottom'}},cutout:'65%'}});

${effort.totalHours > 0
        ? `new Chart(document.getElementById('effortDonut'),{type:'doughnut',data:{
  labels:['Manual','AI Supervised','AI Autonomous'],
  datasets:[{data:[${effort.manualHours},${effort.aiSupervisedHours},${effort.aiAutonomousHours}],
    backgroundColor:[SLDS.gray,SLDS.blue,SLDS.teal],borderWidth:0}]
},options:{plugins:{legend:{position:'bottom'}},cutout:'65%'}});`
        : ''}

new Chart(document.getElementById('burndown'),{type:'line',data:{
  labels:${JSON.stringify(allDays)},
  datasets:[
    {label:'Done',data:${JSON.stringify(burndownDone)},borderColor:SLDS.green,backgroundColor:'rgba(46,132,74,.1)',fill:true,tension:.3},
    {label:'Remaining',data:${JSON.stringify(burndownRemaining)},borderColor:SLDS.blue,backgroundColor:'rgba(1,118,211,.08)',fill:true,tension:.3}
  ]
},options:{plugins:{legend:{position:'bottom'}},scales:{y:{beginAtZero:true}}}});

new Chart(document.getElementById('velocity'),{type:'bar',data:{
  labels:${JSON.stringify(velocityLabels)},
  datasets:[{label:'Tasks/day',data:${JSON.stringify(velocityData)},backgroundColor:SLDS.blue}]
},options:{plugins:{legend:{display:false}},scales:{y:{beginAtZero:true,ticks:{stepSize:1}}}}});

new Chart(document.getElementById('byProfile'),{type:'bar',data:{
  labels:${JSON.stringify(profileLabels)},
  datasets:[
    {label:'Total',data:${JSON.stringify(profileTotals)},backgroundColor:SLDS.blueLight},
    {label:'Done',data:${JSON.stringify(profileDone)},backgroundColor:SLDS.green}
  ]
},options:{indexAxis:'y',plugins:{legend:{position:'bottom'}},scales:{x:{beginAtZero:true,ticks:{stepSize:1}}}}});

new Chart(document.getElementById('phaseTime'),{type:'bar',data:{
  labels:${JSON.stringify(phaseLabels)},
  datasets:[{label:'Avg (h)',data:${JSON.stringify(phaseData)},backgroundColor:SLDS.teal}]
},options:{plugins:{legend:{display:false}},scales:{y:{beginAtZero:true}}}});

${storyLabels.length > 0
        ? `new Chart(document.getElementById('storyCycle'),{type:'bar',data:{
  labels:${JSON.stringify(storyLabels)},
  datasets:[{label:'Hours',data:${JSON.stringify(storyData)},backgroundColor:SLDS.purple}]
},options:{indexAxis:'y',plugins:{legend:{display:false}},scales:{x:{beginAtZero:true}}}});`
        : ''}

${benchWithActuals.length > 0
        ? `// Benchmark charts
const benchLabels=${JSON.stringify(benchWithActuals.map((r) => r.storyId))};
const benchSolo=${JSON.stringify(benchWithActuals.map((r) => r.soloDays))};
const benchUnguided=${JSON.stringify(benchWithActuals.map((r) => r.aiUnguidedDays))};
const benchGuided=${JSON.stringify(benchWithActuals.map((r) => r.aiGuidedDays))};
const benchActual=${JSON.stringify(benchWithActuals.map((r) => r.actualDays))};

new Chart(document.getElementById('benchmarkBar'),{type:'bar',data:{
  labels:benchLabels,
  datasets:[
    {label:'Solo estimate (days)',data:benchSolo,backgroundColor:'rgba(194,57,52,.2)',borderColor:SLDS.red,borderWidth:1,borderRadius:3},
    {label:'AI Unguided est. (days)',data:benchUnguided,backgroundColor:'rgba(1,118,211,.2)',borderColor:SLDS.blue,borderWidth:1,borderRadius:3},
    {label:'AI Guided est. (days)',data:benchGuided,backgroundColor:'rgba(13,157,218,.3)',borderColor:SLDS.teal,borderWidth:1,borderRadius:3},
    {label:'Actual (days)',data:benchActual,backgroundColor:SLDS.green,borderRadius:3}
  ]
},options:{responsive:true,plugins:{legend:{position:'bottom'}},scales:{y:{beginAtZero:true,title:{display:true,text:'Days'}}}}});

const savingsPct=${JSON.stringify(benchWithActuals.map((r) => r.savingsVsSolo))};
new Chart(document.getElementById('savingsBar'),{type:'bar',data:{
  labels:benchLabels,
  datasets:[{label:'Savings vs Solo (%)',data:savingsPct,backgroundColor:savingsPct.map(v=>v>=90?SLDS.green:v>=50?SLDS.orange:SLDS.red),borderRadius:3}]
},options:{responsive:true,plugins:{legend:{display:false}},scales:{y:{title:{display:true,text:'% saved vs solo'}}}}});`
        : ''}
</script>
</body>
</html>`;
}
function escHtml(s) {
    return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
//# sourceMappingURL=dashboard-generator.js.map