"use strict";
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChatQuotaService = void 0;
const copilot_api_1 = require("@vscode/copilot-api");
const event_1 = require("../../../util/vs/base/common/event");
const lifecycle_1 = require("../../../util/vs/base/common/lifecycle");
const authentication_1 = require("../../authentication/common/authentication");
const capiClient_1 = require("../../endpoint/common/capiClient");
const logService_1 = require("../../log/common/logService");
let ChatQuotaService = class ChatQuotaService extends lifecycle_1.Disposable {
    constructor(_authService, _logService, _capiClientService) {
        super();
        this._authService = _authService;
        this._logService = _logService;
        this._capiClientService = _capiClientService;
        this._turnCredits = new Map();
        this._onDidChange = this._register(new event_1.Emitter());
        this.onDidChange = this._onDidChange.event;
        this._rateLimitInfo = { session: undefined, weekly: undefined };
        this._register(this._authService.onDidAuthenticationChange(() => {
            this._processUserInfoQuotaSnapshot(this._authService.copilotToken?.quotaInfo);
        }));
    }
    get quotaInfo() {
        return this._quotaInfo;
    }
    get rateLimitInfo() {
        return this._rateLimitInfo;
    }
    get quotaExhausted() {
        if (!this._quotaInfo) {
            return false;
        }
        if (this._quotaInfo.additionalUsageEnabled) {
            return false;
        }
        // For pooled entitlements (unlimited per-user), has_quota being false signals exhaustion
        if (this._quotaInfo.unlimited) {
            return !this._quotaInfo.hasQuota;
        }
        return this._quotaInfo.percentRemaining <= 0;
    }
    get additionalUsageEnabled() {
        if (!this._quotaInfo) {
            return false;
        }
        return this._quotaInfo.additionalUsageEnabled;
    }
    getCreditsForTurn(turnId) {
        return this._turnCredits.get(turnId);
    }
    setLastCopilotUsage(totalNanoAiu, turnId) {
        // Convert nano-AIUs to AIC credits: 1 AIC = 1_000_000_000 nano-AIU
        const aic = totalNanoAiu / 1_000_000_000;
        if (aic > 0) {
            this._turnCredits.set(turnId, (this._turnCredits.get(turnId) ?? 0) + aic);
        }
    }
    resetTurnCredits(turnId) {
        this._turnCredits.delete(turnId);
    }
    clearQuota() {
        this._quotaInfo = undefined;
    }
    processQuotaHeaders(headers) {
        const quotaHeader = this._authService.copilotToken?.isFreeUser ? headers.get('x-quota-snapshot-chat') : headers.get('x-quota-snapshot-premium_models') || headers.get('x-quota-snapshot-premium_interactions');
        if (!quotaHeader) {
            return;
        }
        const quotaInfo = this._processHeaderValue(quotaHeader);
        if (!quotaInfo) {
            return;
        }
        this._quotaInfo = quotaInfo;
        this._logService.trace(`[ChatQuota] processQuotaHeaders: ${JSON.stringify(quotaInfo)}`);
        const sessionRateLimitHeader = headers.get('x-usage-ratelimit-session');
        const weeklyRateLimitHeader = headers.get('x-usage-ratelimit-weekly');
        this._rateLimitInfo.session = sessionRateLimitHeader ? this._processHeaderValue(sessionRateLimitHeader) : undefined;
        this._rateLimitInfo.weekly = weeklyRateLimitHeader ? this._processHeaderValue(weeklyRateLimitHeader) : undefined;
        this._onDidChange.fire();
    }
    processQuotaSnapshots(snapshots) {
        const snapshot = this._authService.copilotToken?.isFreeUser
            ? snapshots['chat']
            : snapshots['premium_models'] ?? snapshots['premium_interactions'];
        if (!snapshot) {
            return;
        }
        try {
            const entitlement = parseInt(snapshot.entitlement, 10);
            const resetDate = snapshot.reset_date ? new Date(snapshot.reset_date) : (() => { const d = new Date(); d.setMonth(d.getMonth() + 1); return d; })();
            this._quotaInfo = {
                quota: entitlement,
                unlimited: entitlement === -1,
                hasQuota: snapshot.has_quota ?? true,
                percentRemaining: snapshot.percent_remaining,
                additionalUsageUsed: snapshot.overage_count,
                additionalUsageEnabled: snapshot.overage_permitted,
                resetDate,
            };
            this._logService.trace(`[ChatQuota] processQuotaSnapshots: ${JSON.stringify(this._quotaInfo)}`);
            this._onDidChange.fire();
        }
        catch (error) {
            console.error('Failed to process quota snapshots', error);
        }
    }
    async refreshQuota() {
        const githubToken = this._authService.anyGitHubSession?.accessToken;
        if (!githubToken) {
            return;
        }
        try {
            const options = {
                callSite: 'copilot-quota-refresh',
                headers: {
                    Authorization: `token ${githubToken}`,
                    'X-GitHub-Api-Version': '2025-04-01',
                },
                retryFallbacks: true,
                expectJSON: true,
            };
            const response = await this._capiClientService.makeRequest(options, { type: copilot_api_1.RequestType.CopilotUserInfo });
            const data = await response.json();
            this._processUserInfoQuotaSnapshot(data);
            this._logService.trace('[ChatQuota] refreshQuota: fetched up-to-date quota data');
        }
        catch (error) {
            this._logService.trace(`[ChatQuota] refreshQuota: failed to fetch quota data: ${error}`);
        }
    }
    _processHeaderValue(header) {
        try {
            // Parse URL encoded string into key-value pairs
            const params = new URLSearchParams(header);
            // Extract values with fallbacks to ensure type safety
            const entitlement = parseInt(params.get('ent') || '0', 10);
            const additionalUsageUsed = parseFloat(params.get('ov') || '0.0');
            const additionalUsageEnabled = params.get('ovPerm') === 'true';
            const percentRemaining = parseFloat(params.get('rem') || '0.0');
            const resetDateString = params.get('rst');
            let resetDate;
            if (resetDateString) {
                resetDate = new Date(resetDateString);
            }
            else {
                // Default to one month from now if not provided
                resetDate = new Date();
                resetDate.setMonth(resetDate.getMonth() + 1);
            }
            return {
                quota: entitlement,
                unlimited: entitlement === -1,
                hasQuota: true,
                percentRemaining,
                additionalUsageUsed,
                additionalUsageEnabled,
                resetDate,
            };
        }
        catch (error) {
            console.error('Failed to parse quota header', error);
            return undefined;
        }
    }
    _processUserInfoQuotaSnapshot(quotaInfo) {
        if (!quotaInfo || !quotaInfo.quota_snapshots || !quotaInfo.quota_reset_date) {
            return;
        }
        const snapshot = this._authService.copilotToken?.isFreeUser
            ? quotaInfo.quota_snapshots.chat
            : quotaInfo.quota_snapshots.premium_interactions;
        this._quotaInfo = {
            unlimited: snapshot.unlimited,
            hasQuota: snapshot.has_quota ?? true,
            additionalUsageEnabled: snapshot.overage_permitted,
            additionalUsageUsed: snapshot.overage_count,
            quota: snapshot.entitlement,
            resetDate: new Date(quotaInfo.quota_reset_date),
            percentRemaining: snapshot.percent_remaining,
        };
        this._logService.trace(`[ChatQuota] processUserInfoQuotaSnapshot: ${JSON.stringify(this._quotaInfo)}`);
        this._onDidChange.fire();
    }
};
exports.ChatQuotaService = ChatQuotaService;
exports.ChatQuotaService = ChatQuotaService = __decorate([
    __param(0, authentication_1.IAuthenticationService),
    __param(1, logService_1.ILogService),
    __param(2, capiClient_1.ICAPIClientService)
], ChatQuotaService);
//# sourceMappingURL=chatQuotaServiceImpl.js.map