import { existsSync, readFileSync } from 'fs';
import { BRIDGE_LOG_FILE } from './paths.js';
import { t } from './i18n.js';
import { waitBridgeHealth, waitRelayPairingReady } from './launch.js';
export async function fetchRelayRoomDiagnostics(relayUrl, roomId, token) {
    const base = relayUrl.replace(/\/$/, '');
    const q = new URLSearchParams({ roomId });
    if (token)
        q.set('token', token);
    try {
        const res = await fetch(`${base}/api/diagnostics?${q}`, {
            signal: AbortSignal.timeout(12_000),
        });
        if (!res.ok)
            return null;
        const d = (await res.json());
        return {
            ok: Boolean(d.ok),
            connectorInRoom: Boolean(d.connectorInRoom),
            clientsInRoom: Number(d.clientsInRoom ?? 0),
            pairingCodesActive: Number(d.pairingCodesActive ?? 0),
            tokensRegistered: Number(d.tokensRegistered ?? 0),
            tokenRegistered: typeof d.tokenRegistered === 'boolean' ? d.tokenRegistered : null,
            tokenAccepted: typeof d.tokenAccepted === 'boolean' ? d.tokenAccepted : null,
        };
    }
    catch {
        return null;
    }
}
function normalizePairingCode(code) {
    return code.replace(/[^A-Z0-9]/g, '').toUpperCase().slice(0, 6);
}
export function buildStartupReadiness(identity, local, relay, relayReachable) {
    const code = normalizePairingCode(identity.pairingCode);
    const codeExpiresSec = Math.max(0, Math.floor((identity.pairingCodeExpiresAt - Date.now()) / 1000));
    const codeValid = code.length === 6 && codeExpiresSec > 0;
    const connectorInRoom = Boolean(relay?.connectorInRoom);
    const pairingCodesActive = relay?.pairingCodesActive ?? 0;
    const tokensRegistered = relay?.tokensRegistered ?? 0;
    const tokenRegistered = relay?.tokenRegistered === true;
    const ready = local.ok &&
        local.cdp &&
        codeValid &&
        relayReachable &&
        connectorInRoom &&
        pairingCodesActive > 0 &&
        tokensRegistered > 0 &&
        tokenRegistered;
    return {
        localBridgeOk: local.ok,
        localCdp: local.cdp,
        relayReachable,
        connectorInRoom,
        pairingCodesActive,
        tokensRegistered,
        tokenRegistered,
        ready,
        code,
        codeExpiresSec,
        machineLabel: identity.machineLabel,
    };
}
export async function awaitStartupReadiness(relayUrl, identity, opts) {
    const waitMs = opts?.waitMs ?? 45_000;
    const health = await waitBridgeHealth(Math.min(waitMs, 25_000), {
        requireCdp: opts?.requireCdp === true,
    });
    let relayReachable = false;
    try {
        const res = await fetch(`${relayUrl.replace(/\/$/, '')}/health`, {
            signal: AbortSignal.timeout(8_000),
        });
        relayReachable = res.ok;
    }
    catch {
        relayReachable = false;
    }
    await waitRelayPairingReady(relayUrl, identity.roomId, waitMs, identity.clientToken);
    const relay = await fetchRelayRoomDiagnostics(relayUrl, identity.roomId, identity.clientToken);
    return buildStartupReadiness(identity, { ok: health.ok, cdp: health.cdp }, relay, relayReachable);
}
export async function snapshotStartupReadiness(relayUrl, identity) {
    let local = { ok: false, cdp: false };
    try {
        const res = await fetch('http://127.0.0.1:3847/health', {
            signal: AbortSignal.timeout(3_000),
        });
        if (res.ok) {
            const j = (await res.json());
            local = { ok: Boolean(j.ok), cdp: Boolean(j.cdp) };
        }
    }
    catch {
        /* ignore */
    }
    let relayReachable = false;
    try {
        const res = await fetch(`${relayUrl.replace(/\/$/, '')}/health`, {
            signal: AbortSignal.timeout(8_000),
        });
        relayReachable = res.ok;
    }
    catch {
        relayReachable = false;
    }
    const relay = await fetchRelayRoomDiagnostics(relayUrl, identity.roomId, identity.clientToken);
    return buildStartupReadiness(identity, local, relay, relayReachable);
}
export function formatStartupChecklist(r) {
    const mark = (ok) => (ok ? '✓' : '✗');
    const relayLabel = t('readiness.relayLine', {
        state: r.relayReachable
            ? t('readiness.relayReachable')
            : t('readiness.relayUnreachable'),
    });
    const lines = [
        `${mark(r.localBridgeOk)} ${t('readiness.localBridge')}`,
        r.localBridgeOk
            ? r.localCdp
                ? t('readiness.cdpLive')
                : t('readiness.cdpArchiveOnly')
            : t('readiness.runStart'),
        `${mark(r.relayReachable)} ${relayLabel}`,
        `${mark(r.connectorInRoom)} ${t('readiness.macInRoom')}`,
        `${mark(r.pairingCodesActive > 0)} ${t('readiness.codeOnServer')}`,
        r.pairingCodesActive > 0
            ? t('readiness.activeCodes', { count: r.pairingCodesActive })
            : t('readiness.codeNotRegistered'),
        `${mark(r.tokenRegistered)} ${t('readiness.phoneToken')}`,
    ];
    if (r.ready) {
        lines.push('', t('readiness.readyLine', {
            code: r.code,
            minutes: Math.ceil(r.codeExpiresSec / 60),
        }));
    }
    return lines;
}
export function printStartupFailure(r, logPath = BRIDGE_LOG_FILE) {
    console.error('');
    console.error(t('readiness.startupFailed'));
    console.error('');
    for (const line of formatStartupChecklist(r)) {
        console.error(`  ${line}`);
    }
    console.error('');
    if (!r.connectorInRoom) {
        console.error(t('readiness.macNotInRoom'));
    }
    else if (r.pairingCodesActive === 0) {
        console.error(t('readiness.codeNotOnRelay'));
        console.error(t('readiness.doNotReuseCode'));
    }
    else if (!r.tokenRegistered) {
        console.error(t('readiness.tokenNotRegistered'));
    }
    if (!r.localCdp) {
        console.error(t('readiness.cdpUnavailableHint'));
        console.error(t('readiness.cdpLaunchCmd'));
        console.error(t('readiness.thenRestart'));
    }
    if (!r.localBridgeOk) {
        console.error(t('readiness.logPath', { path: logPath }));
        tailLogLines(logPath, 12).forEach((l) => console.error(`    ${l}`));
    }
    console.error('');
}
function tailLogLines(path, n) {
    if (!existsSync(path))
        return [t('readiness.logEmpty')];
    try {
        const raw = readFileSync(path, 'utf-8');
        const lines = raw.trim().split('\n').filter(Boolean);
        return lines.slice(-n);
    }
    catch {
        return [t('readiness.logUnreadable')];
    }
}
