// engine/dashboard/kanban-logic.ts — Kanban business logic (SPEC-122)
// Pure functions for status transitions, grouping, metrics, and health scoring.
/** Ordered list of valid spec statuses */
export const VALID_STATUSES = [
    'draft',
    'review',
    'approved',
    'implementing',
    'done',
    'discarded',
];
/** Valid forward + one-step-back transitions */
export const STATUS_TRANSITIONS = {
    draft: ['review', 'discarded'],
    review: ['approved', 'discarded'],
    approved: ['implementing', 'discarded'],
    implementing: ['done', 'approved', 'discarded'],
    done: ['implementing'],
    discarded: [],
};
/** Check if a status string is a valid spec status */
export function isValidStatus(s) {
    return VALID_STATUSES.includes(s);
}
/** Check if a transition from one status to another is valid */
export function isValidTransition(from, to) {
    if (!isValidStatus(from) || !isValidStatus(to)) {
        return false;
    }
    return STATUS_TRANSITIONS[from]?.includes(to) ?? false;
}
/** Group specs by their status into a Record */
export function groupSpecsByStatus(specs) {
    const groups = {};
    for (const status of VALID_STATUSES) {
        groups[status] = [];
    }
    for (const spec of specs) {
        const statusKey = spec.status;
        if (groups[statusKey]) {
            groups[statusKey].push(spec);
        }
    }
    return groups;
}
/** Check if a column exceeds its WIP limit */
export function isOverWipLimit(column, specs, limits) {
    const limit = limits[column];
    if (limit === undefined) {
        return false;
    }
    const count = specs.filter((s) => s.status === column).length;
    return count > limit;
}
/** Build a standardized update result */
export function buildUpdateResult(success, specId, newStatus, error) {
    const result = { success, specId, newStatus };
    if (error !== undefined) {
        result.error = error;
    }
    return result;
}
/** Compute the percentage of specs with status 'done', excluding discarded from total */
export function computeCompletionRate(specs) {
    const active = specs.filter((s) => s.status !== 'discarded');
    if (active.length === 0) {
        return 0;
    }
    const done = active.filter((s) => s.status === 'done').length;
    return Math.round((done / active.length) * 100);
}
/** Compute the ratio of implemented criteria to total criteria */
export function computeCriteriaCoverage(specs) {
    let totalCriteria = 0;
    let implementedCriteria = 0;
    for (const spec of specs) {
        totalCriteria += spec.criteriaTotal;
        implementedCriteria += spec.criteriaImplemented;
    }
    if (totalCriteria === 0) {
        return 0;
    }
    return Math.round((implementedCriteria / totalCriteria) * 100);
}
/** Compute velocity: specs completed in the last N days (uses updatedAt) */
export function computeVelocity(specs, days) {
    if (days <= 0) {
        return 0;
    }
    const now = Date.now();
    const cutoff = now - days * 24 * 60 * 60 * 1000;
    return specs.filter((s) => {
        if (s.status !== 'done' || !s.updatedAt) {
            return false;
        }
        const ts = new Date(s.updatedAt).getTime();
        return !isNaN(ts) && ts >= cutoff;
    }).length;
}
/** Compute all dashboard metrics from spec data */
export function computeDashboardMetrics(specs, driftScore) {
    return {
        completionRate: computeCompletionRate(specs),
        criteriaCoverage: computeCriteriaCoverage(specs),
        velocity: computeVelocity(specs, 30),
        driftScore: driftScore ?? 0,
    };
}
/**
 * Compute a weighted health score from dashboard metrics.
 * Weights: completion=30, coverage=30, drift=20, velocity=20
 * Drift is inverted (lower drift = better score).
 * Velocity is capped at 100 (10+ specs/month = perfect).
 */
export function computeHealthScore(metrics) {
    const completion = metrics.completionRate;
    const coverage = metrics.criteriaCoverage;
    const drift = Math.max(0, 100 - metrics.driftScore);
    const velocity = Math.min(100, metrics.velocity * 10);
    const overall = Math.round(completion * 0.3 + coverage * 0.3 + drift * 0.2 + velocity * 0.2);
    return {
        overall,
        components: {
            completion,
            coverage,
            drift,
            velocity,
        },
    };
}
//# sourceMappingURL=kanban-logic.js.map