"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TokenController = void 0;
const TokenConfig_1 = require("./TokenControllerUtils/TokenConfig");
const SPComponentsManager_1 = require("./TokenControllerUtils/SPComponentsManager");
const FPComponentsManager_1 = require("./TokenControllerUtils/FPComponentsManager");
const CHComponentsManager_1 = require("./TokenControllerUtils/CHComponentsManager");
const TokenReportBuilder_1 = require("./TokenControllerUtils/TokenReportBuilder");
const TokenView_1 = require("../views/TokenView");
const tiktoken_instance_1 = require("../utils/tiktoken-instance");
const DEFAULT_LIMIT = 1000000;
class TokenController {
    constructor({ systemPromptController, conversationHistoryController, }) {
        this.conversationTLimit = DEFAULT_LIMIT;
        this.tokenConfig = new TokenConfig_1.TokenConfig();
        this.tokenView = new TokenView_1.TokenView();
        this.spTLManager = new SPComponentsManager_1.SPComponentsTLManager(systemPromptController);
        this.fpTLManager = new FPComponentsManager_1.FPComponentsTLManager(systemPromptController);
        this.chTLManager = new CHComponentsManager_1.CHComponentsTLManager(conversationHistoryController);
    }
    handleTokenReport(render = true) {
        return __awaiter(this, void 0, void 0, function* () {
            const tokenReport = yield this.configureTokenReport();
            render && this.tokenView.renderTokenReport(tokenReport);
        });
    }
    getTruncatedConversationhistory() {
        return __awaiter(this, void 0, void 0, function* () {
            const { conversationHistory } = yield this.chTLManager.getCHComponentsTL();
            const spComponentsWithTL = yield this.spTLManager.getSPComponentsTL();
            const tokenUsed = spComponentsWithTL.completeInstructionTokenLength +
                this.tokenConfig.errorCorrectionTokens +
                this.tokenConfig.maxCompletionTokens;
            const tokensRemaining = this.tokenConfig.maxTokens - tokenUsed;
            // truncation logic
            let truncatedCHArry = [...conversationHistory];
            let currCHTokens = yield CHComponentsManager_1.CHComponentsTLManager.calculateTLForCH(truncatedCHArry);
            const controllingLimit = Math.min(this.conversationTLimit, Math.abs(tokensRemaining));
            while (currCHTokens > controllingLimit) {
                truncatedCHArry = truncatedCHArry.slice(1);
                currCHTokens = yield CHComponentsManager_1.CHComponentsTLManager.calculateTLForCH(truncatedCHArry);
            }
            return truncatedCHArry;
        });
    }
    areTheAddedFilesTooLarge() {
        return __awaiter(this, void 0, void 0, function* () {
            const condition = (yield this.getTotalTokensUsed()) > this.tokenConfig.maxTokens;
            if (condition)
                this.tokenView.renderFilesTooLargeError(yield this.configureTokenReport());
            return condition;
        });
    }
    isNLInputTooLarge(input) {
        return __awaiter(this, void 0, void 0, function* () {
            const inputTL = yield (0, tiktoken_instance_1.getTokenLengthByInput)(input);
            const tokenUsed = (yield this.spTLManager.getSPComponentsTL())
                .completeInstructionTokenLength +
                this.tokenConfig.errorCorrectionTokens +
                this.tokenConfig.maxCompletionTokens;
            const tokensRemaining = this.tokenConfig.maxTokens - tokenUsed;
            const tokenRemainingCondition = inputTL > tokensRemaining;
            const tokenRemainingConditionWithLimit = inputTL > this.conversationTLimit;
            if (tokenRemainingCondition) {
                this.tokenView.renderNLInputTooLargeError({ inputTL, tokensRemaining });
            }
            else if (tokenRemainingConditionWithLimit) {
                this.tokenView.headerRender(`The input is **${inputTL}** tokens long`);
                this.tokenView.headerRender(`Use **/tl <number>** to increase the current conversation token limit of **${this.conversationTLimit}**`);
            }
            return tokenRemainingCondition;
        });
    }
    getTokensUsedBySPCH() {
        return __awaiter(this, void 0, void 0, function* () {
            const spComponentsWithTL = yield this.spTLManager.getSPComponentsTL();
            // We dont want the whole history, we want what is being used in the truncation
            // const chComponentsWithTL = await this.chTLManager.getCHComponentsTL();
            const truncatedCHArry = yield this.getTruncatedConversationhistory();
            const chTruncatedTL = yield CHComponentsManager_1.CHComponentsTLManager.calculateTLForCH(truncatedCHArry);
            // SP + CH
            return spComponentsWithTL.completeInstructionTokenLength + chTruncatedTL;
        });
    }
    getTotalTokensUsed() {
        return __awaiter(this, void 0, void 0, function* () {
            const spComponentsWithTL = yield this.spTLManager.getSPComponentsTL();
            // SP + RC + ER
            return (spComponentsWithTL.completeInstructionTokenLength +
                this.tokenConfig.reservedConversationTokens +
                this.tokenConfig.errorCorrectionTokens);
        });
    }
    configureTokenReport() {
        return __awaiter(this, void 0, void 0, function* () {
            const spComponentsWithTL = yield this.spTLManager.getSPComponentsTL();
            const fpComponentsWithTL = yield this.fpTLManager.getFPComponentsWithTLTotalAllFiles();
            const chComponentsWithTL = yield this.chTLManager.getCHComponentsTL();
            const totalTokensUsed = yield this.getTotalTokensUsed();
            const tokenReportBuilder = new TokenReportBuilder_1.TokenReportBuilder(totalTokensUsed, this.tokenConfig, spComponentsWithTL, fpComponentsWithTL, chComponentsWithTL);
            const tokenReport = yield tokenReportBuilder.build();
            return tokenReport;
        });
    }
    handleSetConversationLimit(value) {
        return __awaiter(this, void 0, void 0, function* () {
            let numValue = Number(value);
            if (!Number.isInteger(numValue)) {
                this.tokenView.headerRender(`Input **${numValue}** is not an integer`);
            }
            else if (numValue < 0) {
                this.tokenView.headerRender(`Input **${numValue}** is not a **positive** integer`);
            }
            else {
                this.setConversationLimit(numValue);
                if (this.getConversationLimit() === DEFAULT_LIMIT) {
                    this.tokenView.headerRender(`Conversation token limit is set to **${numValue}** 👍`);
                }
                else {
                    this.tokenView.headerRender(`Conversation token limit is set from **${this.getConversationLimit()}** to **${numValue}** 👍`);
                }
            }
        });
    }
    getConversationLimit() {
        return this.conversationTLimit;
    }
    setConversationLimit(value) {
        this.conversationTLimit = value;
    }
    resetConversationLimit() {
        this.conversationTLimit = 1000000;
    }
}
exports.TokenController = TokenController;
