import { loadTokens, saveTokens } from "./token-storage.js";
import { clearTokens } from "./token-storage.js";
import { refreshTokenViaGateway } from "./gateway-auth.js";
import { logger } from "../utils/logger.js";
/** Refresh tokens 5 minutes (300 seconds) before actual expiry. */
const REFRESH_BUFFER_SECONDS = 300;
/** Check token expiry every 60 seconds. */
const MONITOR_INTERVAL_MS = 60_000;
/**
 * Injectable refresh function. Defaults to refreshTokenViaGateway().
 */
let _refreshFn = refreshTokenViaGateway;
/** Set the token refresh implementation (called during daemon startup). */
export function setRefreshFn(fn) {
    _refreshFn = fn;
}
/**
 * Check whether the stored access token is expired (or will expire within the buffer window).
 * Uses the expires_at field (epoch seconds) from auth.json.
 */
export function isTokenExpired(expiresAt) {
    const now = Math.floor(Date.now() / 1000);
    return now >= expiresAt - REFRESH_BUFFER_SECONDS;
}
/**
 * Refresh the token if it is expired or about to expire.
 * Loads tokens from auth.json, checks expiry, refreshes via Gateway if needed,
 * and saves the updated tokens back to auth.json.
 *
 * Returns true if tokens were refreshed, false if they were still valid.
 * Throws if no tokens are stored.
 */
export async function refreshTokenIfNeeded() {
    const tokens = await loadTokens();
    if (!tokens) {
        throw new Error("No auth tokens found. Please login first.");
    }
    if (!isTokenExpired(tokens.expires_at)) {
        return false;
    }
    logger.info("Access token expired or expiring soon, refreshing...");
    try {
        const session = await _refreshFn(tokens.refresh_token);
        await saveTokens({
            machine_key: tokens.machine_key,
            access_token: session.access_token,
            refresh_token: session.refresh_token,
            expires_at: session.expires_at,
            user_id: tokens.user_id,
        });
        logger.info("Token refreshed successfully");
        return true;
    }
    catch {
        logger.error("Token refresh failed, clearing tokens");
        await clearTokens();
        throw new Error("Failed to refresh token. Tokens cleared. Please login again.");
    }
}
/**
 * Get a valid access token, refreshing if needed.
 * Returns the current access_token string.
 * Throws if no tokens are stored or refresh fails.
 */
export async function getValidAccessToken() {
    await refreshTokenIfNeeded();
    const tokens = await loadTokens();
    if (!tokens) {
        throw new Error("No auth tokens found. Please login first.");
    }
    return tokens.access_token;
}
// ── Token Monitor ──────────────────────────────────────────────────────
let monitorInterval = null;
/**
 * Run a single monitoring check. Attempts to refresh the token if needed.
 * Errors are logged but not thrown — the monitor continues running.
 */
async function monitorCheck() {
    try {
        const refreshed = await refreshTokenIfNeeded();
        if (refreshed) {
            logger.info("Token monitor: refreshed access token");
        }
    }
    catch (err) {
        logger.error(`Token monitor: ${err instanceof Error ? err.message : String(err)}`);
    }
}
/**
 * Start the periodic token monitor. Checks token expiry every 60 seconds
 * and refreshes 5 minutes before expiry.
 */
export function startTokenMonitor() {
    if (monitorInterval) {
        return;
    }
    logger.debug("Starting token monitor (checking every 60s)");
    monitorInterval = setInterval(() => {
        void monitorCheck();
    }, MONITOR_INTERVAL_MS);
    if (monitorInterval.unref) {
        monitorInterval.unref();
    }
}
/**
 * Stop the periodic token monitor.
 */
export function stopTokenMonitor() {
    if (monitorInterval) {
        clearInterval(monitorInterval);
        monitorInterval = null;
        logger.debug("Token monitor stopped");
    }
}
//# sourceMappingURL=token-refresh.js.map