/**
 * Pure Block Kit primitives + score/format helpers + dashboard link builders.
 * No I/O, no env. Every function is a total map from values to JSON / strings.
 *
 * Dashboard route shapes mirror apps/dashboard/src/lib/router-links.ts (D0044).
 */
// --- text objects ----------------------------------------------------------
export function mrkdwn(text) {
    return { type: "mrkdwn", text };
}
export function plainText(text) {
    return { type: "plain_text", text };
}
// --- blocks ----------------------------------------------------------------
export function header(text) {
    return { type: "header", text: plainText(text) };
}
export function section(text) {
    return { type: "section", text: mrkdwn(text) };
}
export function markdown(text) {
    return { type: "markdown", text };
}
export function sectionFields(fields) {
    return { type: "section", fields: fields.map(mrkdwn) };
}
export function context(...parts) {
    return { type: "context", elements: parts.map(mrkdwn) };
}
export function divider() {
    return { type: "divider" };
}
export function actions(elements) {
    return { type: "actions", elements };
}
// --- action contract -------------------------------------------------------
/**
 * Wire `action_id` for the Acknowledge action — the one interactive action the
 * gateway handles today (`POST /v1/slack/interactions`). Single-sourced here so
 * the producer (this factory) and the consumer (`packages/api` routes/slack.ts)
 * cannot drift: that drift is exactly what made every Acknowledge click no-op.
 *
 * @see docs/design-docs/slack-interactivity-endpoint.md
 */
export const SLACK_ACK_ACTION_ID = "acknowledge_alert";
// --- action elements -------------------------------------------------------
export function linkButton(text, url, opts = {}) {
    return {
        type: "button",
        text: plainText(text),
        url,
        ...(opts.style ? { style: opts.style } : {}),
    };
}
export function actionButton(text, value, opts = {}) {
    return {
        type: "button",
        text: plainText(text),
        value,
        ...(opts.style ? { style: opts.style } : {}),
        ...(opts.actionId ? { action_id: opts.actionId } : {}),
        ...(opts.confirm ? { confirm: opts.confirm } : {}),
    };
}
export function overflow(options, actionId) {
    return {
        type: "overflow",
        ...(actionId ? { action_id: actionId } : {}),
        options: options.map((o) => ({ text: plainText(o.text), value: o.value })),
    };
}
// --- score / format helpers ------------------------------------------------
/** Score-band dot, design bands: >=80 green, >=60 yellow, else red. */
export function scoreDot(score) {
    if (score >= 80)
        return ":large_green_circle:";
    if (score >= 60)
        return ":large_yellow_circle:";
    return ":red_circle:";
}
/** 10-cell unicode bar, filled proportionally to score/100. */
export function scoreBar(score) {
    const n = Math.max(0, Math.min(10, Math.round(score / 10)));
    return "█".repeat(n) + "░".repeat(10 - n);
}
/** "+5" / "-3" / "0". */
export function signedDelta(n) {
    if (n > 0)
        return `+${n}`;
    if (n < 0)
        return `${n}`;
    return "0";
}
/** Above-noise up/down triangle, or the within-noise bar. Threshold floored at 1. */
export function noiseArrow(delta, noiseThreshold) {
    const t = Math.max(1, noiseThreshold);
    if (delta >= t)
        return "🔺";
    if (delta <= -t)
        return "🔻";
    return "▬";
}
/** Per-area change glyph for the comparison block. */
export function changeIcon(change) {
    if (change === "improved")
        return "🔼";
    if (change === "regressed")
        return "🔻";
    if (change === "not-evaluated")
        return "—";
    return "▬";
}
/** Compact token count: 1.28M / 842k / 940. */
export function fmtTokens(n) {
    if (n >= 1e6)
        return `${(n / 1e6).toFixed(2)}M`;
    if (n >= 1e3)
        return `${Math.round(n / 1e3)}k`;
    return `${n}`;
}
/** Pipeline duration as "10m 12s" (seconds zero-padded). */
export function formatDuration(ms) {
    const totalSeconds = Math.round(ms / 1000);
    const minutes = Math.floor(totalSeconds / 60);
    const seconds = totalSeconds % 60;
    return `${minutes}m ${String(seconds).padStart(2, "0")}s`;
}
// --- dashboard links -------------------------------------------------------
function normalizeBase(baseUrl) {
    return baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
}
export function reportUrl(baseUrl, reportId) {
    return `${normalizeBase(baseUrl)}?view=report&id=${encodeURIComponent(reportId)}`;
}
export function trendsUrl(baseUrl) {
    return `${normalizeBase(baseUrl)}?view=analytics`;
}
export function runUrl(baseUrl, requestId) {
    return `${normalizeBase(baseUrl)}?view=run&id=${encodeURIComponent(requestId)}`;
}
