/**
 * sinks/slack/format.ts
 *
 * Formats evaluation report data into Slack Block Kit structures for the
 * SlackSink. Provides three message formats:
 *
 * - `formatRegressionAlert` — detailed regression notification with
 *   per-area dimension breakdowns
 * - `formatScoreSummary` — compact score overview for general reporting
 * - `formatWeeklyDigest` — weekly trend summary for scheduled digests
 *
 * @see docs/design-docs/report-store/sink-architecture.md
 */
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
/**
 * Format a regression alert for areas that have regressed.
 *
 * Produces a rich Slack message with:
 * - Header with overall score change
 * - Context metadata (mode, source, timestamp, promptfoo link)
 * - Per-area regression details with dimension breakdowns
 * - Brief mentions of improved and unchanged areas
 */
export function formatRegressionAlert(report) {
    const { comparison, provenance, summary } = report;
    if (!comparison) {
        return {
            blocks: [
                {
                    text: { text: "⚠️ No comparison data available", type: "mrkdwn" },
                    type: "section",
                },
            ],
            text: "No comparison data available",
        };
    }
    const baselineScore = Math.round(comparison.baseline.overall.avgScore);
    const experimentScore = Math.round(comparison.experiment.overall.avgScore);
    const delta = Math.round(comparison.deltas.overall);
    const blocks = [];
    // Header — emoji + title + overall score change
    blocks.push({
        text: {
            text: `📉 *AI Literacy Score Regression*\n` +
                `Overall: ${baselineScore} → ${experimentScore} (${formatDelta(delta)})`,
            type: "mrkdwn",
        },
        type: "section",
    });
    // Context — mode, source, timestamp, promptfoo link
    const contextElements = [
        { text: `*Mode:* ${provenance.mode}`, type: "mrkdwn" },
        { text: `*Source:* ${provenance.source.name}`, type: "mrkdwn" },
        { text: `*Date:* ${readableDate(summary.timestamp)}`, type: "mrkdwn" },
    ];
    if (provenance.promptfooUrls && provenance.promptfooUrls.length > 0) {
        for (const entry of provenance.promptfooUrls) {
            contextElements.push({
                text: `<${entry.url}|Promptfoo (${entry.mode})>`,
                type: "mrkdwn",
            });
        }
    }
    else if (provenance.promptfooUrl) {
        contextElements.push({
            text: `<${provenance.promptfooUrl}|View in Promptfoo>`,
            type: "mrkdwn",
        });
    }
    blocks.push({ elements: contextElements, type: "context" });
    // Divider
    blocks.push({ type: "divider" });
    // Regressed areas — detailed fields with dimension breakdowns
    const regressedAreas = comparison.areas.filter((a) => a.change === "regressed");
    if (regressedAreas.length > 0) {
        const fields = regressedAreas.map((area) => ({
            text: `*${area.area}:* ${Math.round(area.baseline)} → ` +
                `${Math.round(area.experiment)} (${formatDelta(Math.round(area.delta))})\n` +
                dimensionBreakdown(area.dimensions),
            type: "mrkdwn",
        }));
        blocks.push({
            fields,
            text: {
                text: `*Regressed Areas (${regressedAreas.length})*`,
                type: "mrkdwn",
            },
            type: "section",
        });
    }
    // Improved areas — compact mention
    if (comparison.improved.length > 0) {
        blocks.push({
            text: {
                text: `📈 ${comparison.improved.length} area${comparison.improved.length === 1 ? "" : "s"} improved: ${comparison.improved.join(", ")}`,
                type: "mrkdwn",
            },
            type: "section",
        });
    }
    // Unchanged areas — brief mention
    if (comparison.unchanged.length > 0) {
        blocks.push({
            text: {
                text: `➡️ ${comparison.unchanged.length} area${comparison.unchanged.length === 1 ? "" : "s"} unchanged`,
                type: "mrkdwn",
            },
            type: "section",
        });
    }
    // Not-evaluated areas — informational mention
    if (comparison.notEvaluated?.length > 0) {
        blocks.push({
            text: {
                text: `⏭️ ${comparison.notEvaluated.length} area${comparison.notEvaluated.length === 1 ? "" : "s"} not evaluated: ${comparison.notEvaluated.join(", ")}`,
                type: "mrkdwn",
            },
            type: "section",
        });
    }
    return {
        blocks,
        text: `📉 AI Literacy Score Regression: ${baselineScore} → ${experimentScore} (${formatDelta(delta)})`,
    };
}
/**
 * Format a general score summary for Slack reporting.
 *
 * Produces a compact overview with:
 * - Overall score with grade emoji
 * - Per-area score table
 * - Cost summary (if available)
 * - Promptfoo link (if available)
 */
export function formatScoreSummary(report) {
    const { provenance, summary } = report;
    const overall = Math.round(summary.overall.avgScore);
    const blocks = [];
    // Header — overall score with emoji
    blocks.push({
        text: {
            text: `${gradeEmoji(overall)} *AI Literacy Score: ${overall}*`,
            type: "mrkdwn",
        },
        type: "section",
    });
    // Context — mode, source
    const contextElements = [
        { text: `*Mode:* ${provenance.mode}`, type: "mrkdwn" },
        { text: `*Source:* ${provenance.source.name}`, type: "mrkdwn" },
        { text: `*Date:* ${readableDate(summary.timestamp)}`, type: "mrkdwn" },
    ];
    blocks.push({ elements: contextElements, type: "context" });
    // Divider
    blocks.push({ type: "divider" });
    // Per-area score table as markdown
    const rows = summary.scores
        .map((s) => {
        const emoji = gradeEmoji(s.totalScore);
        return `${emoji} *${s.feature}*: ${Math.round(s.totalScore)}  _(T:${Math.round(s.taskCompletion)} · C:${Math.round(s.codeCorrectness)} · D:${Math.round(s.docCoverage)})_`;
    })
        .join("\n");
    blocks.push({
        text: { text: rows, type: "mrkdwn" },
        type: "section",
    });
    // Cost summary
    if (summary.overall.cost) {
        blocks.push({
            text: {
                text: `💰 Total cost: $${summary.overall.cost.total.toFixed(2)} ($${summary.overall.cost.perTest.toFixed(3)}/test)`,
                type: "mrkdwn",
            },
            type: "section",
        });
    }
    // Promptfoo links
    if (provenance.promptfooUrls && provenance.promptfooUrls.length > 0) {
        const links = provenance.promptfooUrls
            .map((e) => `<${e.url}|${e.mode}>`)
            .join(" · ");
        blocks.push({
            text: {
                text: `🔗 View results in Promptfoo: ${links}`,
                type: "mrkdwn",
            },
            type: "section",
        });
    }
    else if (provenance.promptfooUrl) {
        blocks.push({
            text: {
                text: `🔗 <${provenance.promptfooUrl}|View full results in Promptfoo>`,
                type: "mrkdwn",
            },
            type: "section",
        });
    }
    return {
        blocks,
        text: `${gradeEmoji(overall)} AI Literacy Score: ${overall}`,
    };
}
/**
 * Format a weekly digest summary for Slack.
 *
 * Produces a summary message covering score trends over a time window:
 * - Header with overall trend direction and score
 * - Per-area trend table with arrows
 * - Lists of improved, regressed, and stable areas
 * - Report count and time window metadata
 */
export function formatWeeklyDigest(digest) {
    const trendEmoji = digest.overallTrend === "improving"
        ? "📈"
        : digest.overallTrend === "regressing"
            ? "📉"
            : "➡️";
    const blocks = [];
    // Header — overall trend
    blocks.push({
        text: {
            text: `${trendEmoji} *Weekly AI Literacy Digest*\n` +
                `Overall: ${Math.round(digest.overallLatest)} (${formatDelta(Math.round(digest.overallDelta))} this week)`,
            type: "mrkdwn",
        },
        type: "section",
    });
    // Context — time window and report count
    blocks.push({
        elements: [
            {
                text: `*Period:* ${readableDate(digest.lookbackStart)} – ${readableDate(digest.lookbackEnd)}`,
                type: "mrkdwn",
            },
            {
                text: `*Reports:* ${digest.reportCount}`,
                type: "mrkdwn",
            },
        ],
        type: "context",
    });
    blocks.push({ type: "divider" });
    // Per-area trend table
    if (digest.areaTrends.length > 0) {
        const rows = digest.areaTrends
            .map((t) => {
            const arrow = t.trend === "improving" ? "↑" : t.trend === "regressing" ? "↓" : "→";
            const emoji = gradeEmoji(t.lastScore);
            return `${emoji} *${t.area}*: ${Math.round(t.lastScore)} ${arrow} (${formatDelta(Math.round(t.scoreDelta))})`;
        })
            .join("\n");
        blocks.push({
            text: { text: rows, type: "mrkdwn" },
            type: "section",
        });
    }
    // Summary badges
    if (digest.improved.length > 0) {
        blocks.push({
            text: {
                text: `📈 *Improved:* ${digest.improved.join(", ")}`,
                type: "mrkdwn",
            },
            type: "section",
        });
    }
    if (digest.regressed.length > 0) {
        blocks.push({
            text: {
                text: `📉 *Regressed:* ${digest.regressed.join(", ")}`,
                type: "mrkdwn",
            },
            type: "section",
        });
    }
    if (digest.stable.length > 0) {
        blocks.push({
            text: {
                text: `➡️ *Stable:* ${digest.stable.join(", ")}`,
                type: "mrkdwn",
            },
            type: "section",
        });
    }
    // Cost summary if available
    if (digest.totalCost !== undefined) {
        blocks.push({
            text: {
                text: `💰 Total evaluation cost this week: ${digest.totalCost.toFixed(2)}`,
                type: "mrkdwn",
            },
            type: "section",
        });
    }
    return {
        blocks,
        text: `${trendEmoji} Weekly AI Literacy Digest: ${Math.round(digest.overallLatest)} (${formatDelta(Math.round(digest.overallDelta))})`,
    };
}
/** Build a dimension breakdown string for an area delta */
function dimensionBreakdown(dimensions) {
    return [
        `Task: ${formatDelta(dimensions.taskCompletion.delta)}`,
        `Code: ${formatDelta(dimensions.codeCorrectness.delta)}`,
        `Docs: ${formatDelta(dimensions.docCoverage.delta)}`,
    ].join(" · ");
}
/** Format a numeric delta with explicit sign: "+4", "-2", or "0" */
function formatDelta(n) {
    if (n > 0)
        return `+${n}`;
    if (n < 0)
        return `${n}`;
    return "0";
}
/** Score-tier emoji: ✅ (≥80), 🟡 (≥70), 🟠 (≥50), 🔴 (<50) */
function gradeEmoji(score) {
    if (score >= 80)
        return "✅";
    if (score >= 70)
        return "🟡";
    if (score >= 50)
        return "🟠";
    return "🔴";
}
/** Format an ISO timestamp into a readable date string */
function readableDate(iso) {
    const d = new Date(iso);
    return d.toLocaleDateString("en-US", {
        day: "numeric",
        month: "short",
        year: "numeric",
    });
}
