/**
 * P2-6 — dashboard heartbeat merger.
 *
 * The dashboard's per-monitor sparkline previously read `take: 60` raw
 * heartbeats. At 1 check/min that's ~1 hour of history but ~60 rows of
 * read load. P2-6 switches to (latest raw + 24 hourly aggregates) for
 * 24 hours of history at 1/60th the DB load.
 *
 * This helper merges the two into the shape the existing client expects:
 *   - heartbeats[0] is the most recent (raw) — current status read here
 *   - heartbeats[1..N] are hourly aggregates rendered as the sparkline
 *
 * Aggregates don't carry per-check TLS info, so synthetic rows surface
 * NULL there; the dashboard already handles null TLS gracefully.
 */

export type DashHeartbeat = {
    id: number;
    status: 'up' | 'down' | 'maintenance' | 'pending';
    responseTimeMs: number | null;
    createdAt: Date;
    tlsValid: boolean | null;
    tlsExpiresAt: Date | null;
    tlsIssuer: string | null;
};

export type RawHeartbeat = {
    id: number;
    status: string;
    responseTimeMs: number | null;
    createdAt: Date;
    tlsValid?: boolean | null;
    tlsExpiresAt?: Date | null;
    tlsIssuer?: string | null;
} | null;

export type HourlyAggregate = {
    timestamp: Date;
    avgLatency: number;
    uptimePercent: number;
    totalChecks: number;
};

/** uptimePercent threshold above which an aggregate counts as "up" on the sparkline. */
const UP_THRESHOLD = 99;

let syntheticIdCounter = -1;
function nextSyntheticId(): number {
    return syntheticIdCounter--;
}

export function mergeDashboardHeartbeats(
    latestRaw: RawHeartbeat,
    hourlies: HourlyAggregate[]
): DashHeartbeat[] {
    const out: DashHeartbeat[] = [];

    if (latestRaw) {
        out.push({
            id: latestRaw.id,
            status: (latestRaw.status as DashHeartbeat['status']) || 'pending',
            responseTimeMs: latestRaw.responseTimeMs ?? null,
            createdAt: latestRaw.createdAt,
            tlsValid: latestRaw.tlsValid ?? null,
            tlsExpiresAt: latestRaw.tlsExpiresAt ?? null,
            tlsIssuer: latestRaw.tlsIssuer ?? null,
        });
    }

    for (const h of hourlies) {
        out.push({
            id: nextSyntheticId(),
            status: h.uptimePercent >= UP_THRESHOLD ? 'up' : 'down',
            responseTimeMs: h.avgLatency,
            createdAt: h.timestamp,
            tlsValid: null,
            tlsExpiresAt: null,
            tlsIssuer: null,
        });
    }

    return out;
}
