"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.ProxyModelsService = void 0;
const util_1 = require("util");
const errors_1 = require("../../../util/common/errors");
const cancellation_1 = require("../../../util/vs/base/common/cancellation");
const event_1 = require("../../../util/vs/base/common/event");
const lifecycle_1 = require("../../../util/vs/base/common/lifecycle");
const observable_1 = require("../../../util/vs/base/common/observable");
const copilotTokenStore_1 = require("../../authentication/common/copilotTokenStore");
const capiClient_1 = require("../../endpoint/common/capiClient");
const inlineEditsModelsTypes_1 = require("../../inlineEdits/common/dataTypes/inlineEditsModelsTypes");
const logService_1 = require("../../log/common/logService");
const fetcherService_1 = require("../../networking/common/fetcherService");
let ProxyModelsService = class ProxyModelsService extends lifecycle_1.Disposable {
    constructor(_tokenStore, _capiClient, _fetchService, _logService) {
        super();
        this._tokenStore = _tokenStore;
        this._capiClient = _capiClient;
        this._fetchService = _fetchService;
        this._logService = _logService;
        this._onModelListUpdated = this._register(new event_1.Emitter());
        this.onModelListUpdated = this._onModelListUpdated.event;
        const copilotTokenObs = (0, observable_1.observableFromEvent)(this, this._tokenStore.onDidStoreUpdate, () => this._tokenStore.copilotToken);
        this._register((0, observable_1.autorun)(reader => {
            const copilotToken = copilotTokenObs.read(reader);
            const cts = new cancellation_1.CancellationTokenSource();
            this._fetchLatestModels(copilotToken, cts.token).then(models => {
                if (models === undefined) {
                    return;
                }
                if (cts.token.isCancellationRequested) {
                    return;
                }
                if ((0, util_1.isDeepStrictEqual)(this._models, models)) {
                    return;
                }
                this._models = models;
                this._onModelListUpdated.fire();
            }).catch((e) => {
                const err = errors_1.ErrorUtils.fromUnknown(e);
                this._logService.error(err, 'Failed to fetch models in autorun');
            });
            reader.store.add({ dispose: () => cts.dispose(true) });
        }));
    }
    get models() {
        return this._models;
    }
    get nesModels() {
        return this._models?.models.filter(model => model.serviceType === 'NESChat');
    }
    get cursorJumpModels() {
        return this._models?.models.filter(model => model.serviceType === 'CursorJumpChat');
    }
    get instantApplyModels() {
        return this._models?.models.filter(model => model.serviceType === 'InstantApplyChat');
    }
    async _fetchLatestModels(copilotToken, token) {
        if (!copilotToken) {
            return undefined;
        }
        const url = `${this._capiClient.proxyBaseURL}/models`;
        const abortController = this._fetchService.makeAbortController();
        const disposable = token.onCancellationRequested(() => abortController.abort());
        let r;
        try {
            r = await this._fetchService.fetch(url, {
                headers: {
                    'Authorization': `Bearer ${copilotToken.token}`,
                },
                method: 'GET',
                timeout: 10_000,
                callSite: 'proxy-models',
                signal: abortController.signal,
            });
        }
        catch (e) {
            const err = errors_1.ErrorUtils.fromUnknown(e);
            this._logService.error(err, 'Failed to fetch model list');
            return;
        }
        finally {
            disposable.dispose();
        }
        if (!r.ok) {
            this._logService.error(`Failed to fetch model list: ${r.status} ${r.statusText}`);
            return;
        }
        try {
            const jsonData = await r.json();
            const validatedData = inlineEditsModelsTypes_1.WireTypes.ModelList.validator.validate(jsonData);
            if (validatedData.error) {
                throw new Error(`Invalid /models response data: ${validatedData.error.message}`); // TODO@ulugbekna: add telemetry
            }
            return validatedData.content;
        }
        catch (e) {
            const err = errors_1.ErrorUtils.fromUnknown(e);
            this._logService.error(err, 'Failed to process /models response');
            return;
        }
    }
};
exports.ProxyModelsService = ProxyModelsService;
exports.ProxyModelsService = ProxyModelsService = __decorate([
    __param(0, copilotTokenStore_1.ICopilotTokenStore),
    __param(1, capiClient_1.ICAPIClientService),
    __param(2, fetcherService_1.IFetcherService),
    __param(3, logService_1.ILogService)
], ProxyModelsService);
//# sourceMappingURL=proxyModelsService.js.map