/**
 * P1-1 smoke test — retryIntervalSeconds shortens the gap between
 * failed checks until the confirmed-down threshold is reached.
 *
 * Run: npx tsx scripts/smoke/p1-1-retry-interval.ts
 */
import './_lib';
import { ok, fail } from './_lib';

const prismaMod = require('../../src/lib/prisma') as { prisma: Record<string, unknown> };

let recentDownCount = 0;
let lastUpdate: { data: { nextCheckAt: Date } } | null = null;

prismaMod.prisma.heartbeat = {
    create: async () => ({ id: 1, createdAt: new Date(), responseTimeMs: 50, status: 'down' }),
    count: async () => recentDownCount,
    // Auditor T2G (2026-06-01): a single bounded findMany now serves both
    // the retry-interval count AND the state-eval historyBefore. Returning
    // a `recentDownCount`-long array of downs drives the retry-window slice
    // (first `retries + 1` rows). The state-eval branch sees the same rows
    // filtered to exclude the just-saved heartbeat; since none of these
    // mock rows carries `id`, none equals the saved id (1) → all pass through.
    findMany: async () =>
        Array.from({ length: recentDownCount }, () => ({ status: 'down' })),
} as unknown;
prismaMod.prisma.monitor = {
    update: async (args: { data: { nextCheckAt: Date } }) => { lastUpdate = args; return null; },
    updateMany: async () => ({ count: 0 }),
    findMany: async () => [],
} as unknown;
prismaMod.prisma.heartbeatHourly = {
    findFirst: async () => null,
    findUnique: async () => null,
    create: async () => null,
    update: async () => null,
    upsert: async () => null,
} as unknown;

// Stub the strategy registry by mocking the strategy class.
const httpStrat = require('../../src/lib/monitor-strategies/http.strategy') as { HttpMonitorStrategy: unknown };
httpStrat.HttpMonitorStrategy = class {
    async check() { return { status: 'down', duration: 50, statusCode: 0, errorMessage: 'fail' }; }
};

// Re-import engine AFTER patching strategy module so its registry uses the
// patched class.
delete require.cache[require.resolve('../../src/lib/monitor-engine')];
const { checkMonitor } = require('../../src/lib/monitor-engine') as typeof import('../../src/lib/monitor-engine');

function monitor(overrides: Record<string, unknown> = {}): import('../../src/types').MonitorForCheck {
    return {
        id: 1, name: 'x', type: 'http', url: 'http://x', hostname: 'x',
        port: null, method: 'GET', headers: null, body: null,
        timeoutSeconds: 5, acceptedStatusCodes: '["200-299"]',
        keyword: null, keywordShouldContain: true, ignoreTlsErrors: false,
        intervalSeconds: 60, retryIntervalSeconds: 10, retries: 3,
        region: 'KE',
        ...overrides,
    } as import('../../src/types').MonitorForCheck;
}

async function main(): Promise<void> {
    recentDownCount = 1;
    lastUpdate = null;
    await checkMonitor(monitor());
    if (!lastUpdate) fail('P1-1 retry window', 'monitor.update never called');
    const elapsed1 = lastUpdate!.data.nextCheckAt.getTime() - Date.now();
    if (elapsed1 < 8_000 || elapsed1 > 12_000) {
        fail('P1-1 retry window', `expected ~10s, got ${elapsed1}ms`);
    }
    ok('Inside retry window → next check in ~10s (retryIntervalSeconds)');

    recentDownCount = 3;
    lastUpdate = null;
    await checkMonitor(monitor());
    const elapsed2 = lastUpdate!.data.nextCheckAt.getTime() - Date.now();
    if (elapsed2 < 58_000 || elapsed2 > 62_000) {
        fail('P1-1 confirmed', `expected ~60s, got ${elapsed2}ms`);
    }
    ok('Past retry window → next check in ~60s (intervalSeconds)');

    recentDownCount = 0;
    lastUpdate = null;
    await checkMonitor(monitor({ retryIntervalSeconds: 0 }));
    const elapsed3 = lastUpdate!.data.nextCheckAt.getTime() - Date.now();
    if (elapsed3 < 58_000) {
        fail('P1-1 feature-off', `retryIntervalSeconds=0 should disable, got ${elapsed3}ms`);
    }
    ok('retryIntervalSeconds=0 disables feature');

    ok('P1-1 retry-interval', 'failed-check retry uses retryIntervalSeconds while in window');
}

main().catch((err) => fail('P1-1 retry-interval', String(err)));
