import { loadOwnerConfig, buildPricingUrl } from "../../config/index.js";
import { getAgentState } from "../state.js";
import { logger } from "../../logger.js";
const GATE_POLL_INTERVAL_MS = 10_000;
const GATE_REMINDER_INTERVAL_MS = 30 * 60 * 1000; // 30 minutes between periodic reminders
export const USAGE_GATE_MESSAGE = "Your WorkUnit (WU) allowance for this period has been used up. Please upgrade your plan or buy a WU bundle to continue.";
// wuUsed / wuLimit / bundleWuRemaining are stored in mWU (1 WU = 1000 mWU).
// Display in WU. The onboarding service's formatWu lives in a separate package
// we can't import here, so the /1000 conversion is inlined.
function formatWu(mwu) {
    return (mwu / 1000).toLocaleString("en-US", { maximumFractionDigits: 2 });
}
function formatUsageContext(usageStatus) {
    if (!usageStatus)
        return "";
    const parts = [];
    if (usageStatus.wuLimit !== null) {
        parts.push(`${formatWu(usageStatus.wuUsed)} / ${formatWu(usageStatus.wuLimit)} WU used`);
    }
    else {
        parts.push(`${formatWu(usageStatus.wuUsed)} WU used`);
    }
    if (usageStatus.bundleWuRemaining > 0) {
        parts.push(`${formatWu(usageStatus.bundleWuRemaining)} bundle WU remaining`);
    }
    return parts.join(" · ");
}
/**
 * Determine whether the usage gate should block new Claude wake cycles.
 *
 * The usage gate is subordinate to the billing/subscription gate:
 *  - If billing is "skip" (disabled), the usage gate is never enforced,
 *    regardless of metered usage.
 *  - If billing is "expired", the subscription gate takes priority; the
 *    usage gate should not fire until the subscription is resolved.
 *
 * Enforcement requires ALL of:
 *  - subscriptionStatus is "active" (billing is on and subscription valid)
 *  - status is "exhausted" (WU used >= available WU)
 *  - coverage is "complete" or "cutover" — meaning the server has
 *    sufficient data to trust the metering result. "partial" coverage
 *    is intentionally excluded because historical data may be incomplete
 *    and gating the user on inaccurate numbers would be wrong.
 */
export function shouldEnforceUsageGate(usageStatus, subscriptionStatus) {
    // Usage gate only applies when billing is active. "skip" means billing
    // is turned off; "expired" is handled by the subscription gate first.
    if (subscriptionStatus !== "active")
        return false;
    return usageStatus?.status === "exhausted" && (usageStatus.coverage === "complete" || usageStatus.coverage === "cutover");
}
export async function runUsageGate(config, channelManager, heartbeat) {
    const ownerConfig = loadOwnerConfig();
    const agentState = getAgentState();
    agentState.gated = true;
    try {
        logger.system("Usage exhausted — entering usage gate (no Claude API calls)");
        const pricingUrl = buildPricingUrl(config);
        const usageContext = formatUsageContext(heartbeat.lastUsageStatus);
        const message = usageContext
            ? `${USAGE_GATE_MESSAGE}\n\n${usageContext}\n\nBrowse plans or top up: ${pricingUrl}`
            : `${USAGE_GATE_MESSAGE}\n\nBrowse plans or top up: ${pricingUrl}`;
        try {
            if (ownerConfig.telegramChatId) {
                const plans = heartbeat.lastBillingPlans;
                if (plans.length > 0) {
                    await channelManager.sendTelegramPaymentPrompt(ownerConfig.telegramChatId, { message, plans });
                }
                else {
                    await channelManager.sendMessage("telegram", String(ownerConfig.telegramChatId), message);
                }
            }
            else if (ownerConfig.ownerEmail) {
                await channelManager.sendMessage("gmail", ownerConfig.ownerEmail, message);
            }
        }
        catch {
            logger.warn("Failed to send usage gate notification to owner");
        }
        await heartbeat.stopRuntime();
        try {
            let status = heartbeat.lastUsageStatus;
            let lastReminderAt = Date.now();
            while (status?.status === "exhausted") {
                await new Promise((resolve) => setTimeout(resolve, GATE_POLL_INTERVAL_MS));
                status = await heartbeat.sendHeartbeatForUsageGate();
                if (status?.status !== "exhausted")
                    break;
                if (Date.now() - lastReminderAt >= GATE_REMINDER_INTERVAL_MS) {
                    lastReminderAt = Date.now();
                    const reminderContext = formatUsageContext(status);
                    const reminder = reminderContext
                        ? `Still waiting for WU top-up. ${reminderContext}\n\nBrowse plans: ${pricingUrl}`
                        : `Still waiting for WU top-up.\n\nBrowse plans: ${pricingUrl}`;
                    try {
                        if (ownerConfig.telegramChatId) {
                            await channelManager.sendMessage("telegram", String(ownerConfig.telegramChatId), reminder);
                        }
                    }
                    catch {
                        logger.debug("Failed to send usage gate reminder");
                    }
                }
                logger.debug(`Usage gate: still exhausted, polling again in ${GATE_POLL_INTERVAL_MS / 1000}s`);
            }
        }
        finally {
            heartbeat.startRuntime(() => agentState.busy);
        }
        logger.system("Usage gate cleared — exiting usage gate");
        try {
            if (ownerConfig.telegramChatId) {
                await channelManager.sendMessage("telegram", String(ownerConfig.telegramChatId), "Usage balance updated. I can continue now.");
            }
        }
        catch {
            logger.warn("Failed to send usage gate cleared notification");
        }
    }
    finally {
        agentState.gated = false;
    }
}
//# sourceMappingURL=usage-gate.js.map