"use strict";
/**
 * Quota Fetcher for GitHub Copilot OAuth (ghcp) Accounts
 *
 * Fetches quota information from GitHub `/copilot_internal/user` endpoint
 * using the account token managed by CLIProxy auth flow.
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractGhcpAccessToken = exports.normalizeGhcpSnapshot = exports.fetchAllGhcpQuotas = exports.fetchGhcpQuota = void 0;
const fs = __importStar(require("node:fs"));
const account_manager_1 = require("../accounts/account-manager");
const percentage_1 = require("../../utils/percentage");
const GHCP_USAGE_URL = 'https://api.github.com/copilot_internal/user';
const GHCP_USAGE_TIMEOUT_MS = 10000;
/**
 * Mirrors headers currently accepted by GitHub Copilot internal usage endpoint.
 * Keep aligned with upstream Copilot client/API changes when quota calls break.
 */
const GHCP_USER_AGENT = 'GitHubCopilotChat/0.26.7';
const GHCP_API_VERSION = '2025-04-01';
function normalizeSnapshot(raw) {
    const unlimited = Boolean(raw?.unlimited);
    const hasPercentSignal = typeof raw?.percent_remaining === 'number' && Number.isFinite(raw.percent_remaining);
    const rawRemaining = typeof raw?.remaining === 'number' ? raw.remaining : raw?.quota_remaining;
    const hasEntitlementRemainingSignal = typeof raw?.entitlement === 'number' &&
        Number.isFinite(raw.entitlement) &&
        raw.entitlement > 0 &&
        typeof rawRemaining === 'number' &&
        Number.isFinite(rawRemaining);
    const reported = raw !== undefined && (unlimited || hasPercentSignal || hasEntitlementRemainingSignal);
    const entitlement = Number(raw?.entitlement ?? 0);
    const remainingRaw = rawRemaining ?? 0;
    const remaining = Number(remainingRaw);
    const safeEntitlement = Number.isFinite(entitlement) ? Math.max(0, entitlement) : 0;
    const safeRemaining = Number.isFinite(remaining) ? Math.max(0, remaining) : 0;
    const used = Math.max(0, safeEntitlement - safeRemaining);
    const percentRemaining = unlimited
        ? 100
        : hasPercentSignal
            ? (0, percentage_1.clampPercent)(raw.percent_remaining)
            : reported && safeEntitlement > 0
                ? (0, percentage_1.clampPercent)((safeRemaining / safeEntitlement) * 100)
                : 0;
    return {
        reported,
        entitlement: safeEntitlement,
        remaining: safeRemaining,
        used,
        percentRemaining,
        percentUsed: (0, percentage_1.clampPercent)(100 - percentRemaining),
        unlimited,
        overageCount: typeof raw?.overage_count === 'number' && Number.isFinite(raw.overage_count)
            ? Math.max(0, raw.overage_count)
            : 0,
        overagePermitted: Boolean(raw?.overage_permitted),
        quotaId: raw?.quota_id || null,
    };
}
exports.normalizeGhcpSnapshot = normalizeSnapshot;
function extractAccessToken(tokenData) {
    if (typeof tokenData.access_token === 'string' && tokenData.access_token.trim()) {
        return tokenData.access_token.trim();
    }
    if (tokenData.token &&
        typeof tokenData.token === 'object' &&
        typeof tokenData.token.access_token === 'string' &&
        tokenData.token.access_token.trim()) {
        return tokenData.token.access_token.trim();
    }
    return null;
}
exports.extractGhcpAccessToken = extractAccessToken;
function readGhcpAccessToken(accountId) {
    const account = (0, account_manager_1.getProviderAccounts)('ghcp').find((item) => item.id === accountId);
    if (!account) {
        return { accessToken: null, error: `Account not found: ${accountId}` };
    }
    const tokenPath = (0, account_manager_1.getAccountTokenPath)(account);
    if (!tokenPath || !fs.existsSync(tokenPath)) {
        return { accessToken: null, error: 'Auth token file not found' };
    }
    try {
        const raw = fs.readFileSync(tokenPath, 'utf-8');
        const data = JSON.parse(raw);
        const accessToken = extractAccessToken(data);
        if (!accessToken) {
            return { accessToken: null, error: 'No access token in auth file' };
        }
        return { accessToken };
    }
    catch (error) {
        return {
            accessToken: null,
            error: error instanceof Error ? error.message : 'Failed to parse auth token file',
        };
    }
}
function buildEmptyQuotaResult(error, accountId) {
    return {
        success: false,
        planType: null,
        quotaResetDate: null,
        snapshots: {
            premiumInteractions: normalizeSnapshot(),
            chat: normalizeSnapshot(),
            completions: normalizeSnapshot(),
        },
        lastUpdated: Date.now(),
        error,
        accountId,
    };
}
function normalizeUsageResponse(raw) {
    const snapshots = raw.quota_snapshots || {};
    return {
        success: true,
        planType: raw.copilot_plan ?? null,
        quotaResetDate: raw.quota_reset_date ?? null,
        snapshots: {
            premiumInteractions: normalizeSnapshot(snapshots.premium_interactions),
            chat: normalizeSnapshot(snapshots.chat),
            completions: normalizeSnapshot(snapshots.completions),
        },
        lastUpdated: Date.now(),
    };
}
/**
 * Fetch quota for one ghcp account.
 */
async function fetchGhcpQuota(accountId, verbose = false) {
    const { accessToken, error } = readGhcpAccessToken(accountId);
    if (!accessToken) {
        // Safe diagnostic: accountId + generic error only (never log token values/file contents).
        if (verbose)
            console.error(`[!] ghcp quota token error (${accountId}): ${error}`);
        return buildEmptyQuotaResult(error || 'Failed to load auth token', accountId);
    }
    if (verbose)
        console.error(`[i] Fetching ghcp quota for ${accountId}...`);
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), GHCP_USAGE_TIMEOUT_MS);
    try {
        const response = await fetch(GHCP_USAGE_URL, {
            method: 'GET',
            signal: controller.signal,
            headers: {
                Accept: 'application/json',
                Authorization: `token ${accessToken}`,
                'User-Agent': GHCP_USER_AGENT,
                'x-github-api-version': GHCP_API_VERSION,
            },
        });
        clearTimeout(timeoutId);
        if (response.status === 401 || response.status === 403) {
            return {
                ...buildEmptyQuotaResult('Authentication expired or invalid', accountId),
                needsReauth: true,
            };
        }
        if (response.status === 429) {
            return buildEmptyQuotaResult('Rate limited - try again later', accountId);
        }
        if (!response.ok) {
            return buildEmptyQuotaResult(`GitHub API error: ${response.status}`, accountId);
        }
        const data = (await response.json());
        return {
            ...normalizeUsageResponse(data),
            accountId,
        };
    }
    catch (error) {
        clearTimeout(timeoutId);
        const message = error instanceof Error && error.name === 'AbortError'
            ? 'Request timeout'
            : error instanceof Error
                ? error.message
                : 'Unknown error';
        return buildEmptyQuotaResult(message, accountId);
    }
}
exports.fetchGhcpQuota = fetchGhcpQuota;
/**
 * Fetch quota for all ghcp accounts.
 */
async function fetchAllGhcpQuotas(verbose = false) {
    const accounts = (0, account_manager_1.getProviderAccounts)('ghcp');
    const results = await Promise.all(accounts.map(async (account) => ({
        account: account.id,
        quota: await fetchGhcpQuota(account.id, verbose),
    })));
    return results;
}
exports.fetchAllGhcpQuotas = fetchAllGhcpQuotas;
//# sourceMappingURL=quota-fetcher-ghcp.js.map