"use strict";
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;
};
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.StateController = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const StateView_1 = require("../views/StateView");
const STATE_FILE = path.join(process.env.HOME, ".cache", "shell-chat.json");
class StateController {
    constructor() {
        this.saveName = "";
        this.stateView = new StateView_1.StateView();
        const exists = fs.existsSync(STATE_FILE);
        if (exists) {
            this.saveFile = JSON.parse(fs.readFileSync(STATE_FILE, "utf-8"));
            // if cache exists, delete it and rewrite savefile for every load
            if (this.saveFile["cache"]) {
                delete this.saveFile["cache"];
                fs.writeFileSync(STATE_FILE, JSON.stringify(this.saveFile, null, 2));
            }
        }
        else {
            this.saveFile = {};
            fs.writeFileSync(STATE_FILE, JSON.stringify(this.saveFile, null, 2));
        }
    }
    renameCurrentState(newName) {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.saveFile[this.saveName]) {
                if (this.saveName === newName) {
                    this.stateView.conversationCannotRenameToSameName(newName);
                    return;
                }
                this.saveFile[newName] = this.saveFile[this.saveName];
                delete this.saveFile[this.saveName];
                yield fs.promises.writeFile(STATE_FILE, JSON.stringify(this.saveFile, null, 2));
                this.stateView.conversationStateRenamed(this.saveName, newName);
                this.saveName = newName;
            }
            else {
                this.stateView.headerRender("Save first prior to renaming");
            }
        });
    }
    moveAndResetCache(saveName) {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.saveFile["cache"]) {
                this.saveFile[saveName] = this.saveFile["cache"];
                delete this.saveFile["cache"];
                yield fs.promises.writeFile(STATE_FILE, JSON.stringify(this.saveFile, null, 2));
            }
            else {
                this.stateView.noSaveFound("cache");
            }
        });
    }
    getSaveName() {
        return this.saveName;
    }
    saveState({ saveName, conversationHistory, trackedFiles, limit, }) {
        return __awaiter(this, void 0, void 0, function* () {
            this.saveFile[saveName] = { conversationHistory, trackedFiles, limit };
            yield fs.promises.writeFile(STATE_FILE, JSON.stringify(this.saveFile, null, 2));
            this.stateView.conversationStateSaved(saveName);
            this.saveName = saveName;
        });
    }
    loadState(saveName, callback) {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.saveFile[saveName]) {
                // Save name exists, load conversation history and tracked files
                const { conversationHistory, trackedFiles, limit } = this.saveFile[saveName];
                // Update conversation history and tracked files in current session
                yield callback(conversationHistory, trackedFiles, limit);
                // notifies user that loading is successful
                this.stateView.conversationStateLoaded(saveName, conversationHistory);
                // then render the current history of the loaded save (as per conversationHistory) and trackedFiles(?)
                this.saveName = saveName;
            }
            else {
                this.stateView.noSaveFound(saveName);
            }
        });
    }
    createEmptyState(saveName, callback) {
        return __awaiter(this, void 0, void 0, function* () {
            this.saveFile[saveName] = {
                conversationHistory: [],
                trackedFiles: [],
                limit: 1000000, // 1 mil token upperlimit
            };
            yield fs.promises.writeFile(STATE_FILE, JSON.stringify(this.saveFile, null, 2));
            this.saveName = saveName;
            yield callback();
            this.stateView.headerRender(`Current conversation saved to **${saveName}**`);
        });
    }
    deleteState(saveName) {
        return __awaiter(this, void 0, void 0, function* () {
            // cannot delete the current state
            if (this.saveName === saveName) {
                this.stateView.headerRender(`Cannot delete the current state **${saveName}**`);
                return;
            }
            if (this.saveFile[saveName]) {
                delete this.saveFile[saveName];
                yield fs.promises.writeFile(STATE_FILE, JSON.stringify(this.saveFile, null, 2));
                this.stateView.conversationStateDeleted(saveName);
            }
            else {
                this.stateView.noSaveFound(saveName);
            }
        });
    }
    deleteAllStates() {
        return __awaiter(this, void 0, void 0, function* () {
            const saveNames = Object.keys(this.saveFile);
            if (saveNames.length === 0) {
                // this.stateView.noSaveFound("any");
                this.stateView.allConversationStatesDeleted();
            }
            else {
                this.saveFile = {};
                this.saveName = "";
                yield fs.promises.writeFile(STATE_FILE, JSON.stringify(this.saveFile, null, 2));
                this.stateView.allConversationStatesDeleted();
            }
        });
    }
    listSavedStates() {
        const saveNames = Object.keys(this.saveFile);
        this.stateView.savedConversationStatesList(saveNames);
    }
    getSavedStateNames() {
        return __awaiter(this, void 0, void 0, function* () {
            return Object.keys(this.saveFile);
        });
    }
    cacheExists() {
        return __awaiter(this, void 0, void 0, function* () {
            return !!this.saveFile["cache"];
        });
    }
    saveStateInterface({ saveName, overwrite = false, conversationHistory, trackedFiles, limit, }) {
        return __awaiter(this, void 0, void 0, function* () {
            const saveNames = yield this.getSavedStateNames();
            const isNameTaken = saveName && saveNames.includes(saveName);
            // cannot overwrite existing save if overwrite flag is not false
            if (isNameTaken && !overwrite) {
                this.stateView.renderSaveOverwrite(saveName);
                return;
            }
            // if saveName is not provided, use the stateSaveName.
            // if the stateSaveName is not available, return early and notify the user
            if (!saveName) {
                if (!this.getSaveName()) {
                    this.stateView.renderNoSaveName();
                    return;
                }
                else {
                    saveName = this.getSaveName();
                }
            }
            yield this.saveState({
                saveName,
                conversationHistory,
                trackedFiles,
                limit,
            });
        });
    }
    moveCacheToSaveInterface({ saveName, overwrite, }) {
        return __awaiter(this, void 0, void 0, function* () {
            const saveNames = yield this.getSavedStateNames();
            const isNameTaken = saveName && saveNames.includes(saveName);
            if (!(yield this.cacheExists())) {
                this.stateView.renderCacheDoesNotExist();
                return;
            }
            if (isNameTaken && !overwrite) {
                this.stateView.renderSaveOverwriteFromCache(saveName);
                return;
            }
            yield this.moveAndResetCache(saveName);
            this.stateView.renderSuccessCacheMove(saveName);
        });
    }
    loadStateInterface({ loadName, loadStateCallback, conversationHistory, trackedFiles, limit, }) {
        return __awaiter(this, void 0, void 0, function* () {
            // keep this in commandcontroller
            // cannot load the cache (for ungodly amounts of simplicity)
            if (loadName === "cache") {
                this.stateView.headerRender("Cannot specifically load the **cache** - sorry 🙇");
                return;
            }
            const savedNames = yield this.getSavedStateNames();
            if (!savedNames.includes(loadName)) {
                this.stateView.conversationStateLoadDoesNotExist(loadName);
                return;
            }
            const currSaveName = this.getSaveName();
            // user trying to load the current state, cannot do this
            if (currSaveName === loadName) {
                this.stateView.renderLoadingAlreadyCurrentState(loadName);
                return;
            }
            if (currSaveName) {
                yield this.saveState({
                    saveName: currSaveName,
                    conversationHistory,
                    trackedFiles,
                    limit,
                });
            }
            else {
                yield this.saveState({
                    saveName: "cache",
                    conversationHistory,
                    trackedFiles,
                    limit,
                });
                this.stateView.renderSavedToCacheBeforeLoad();
            }
            yield this.loadState(loadName, loadStateCallback);
        });
    }
    newStateInterface({ newStateName, newStateCallback, conversationHistory, trackedFiles, limit, }) {
        return __awaiter(this, void 0, void 0, function* () {
            if (newStateName === "cache") {
                this.stateView.headerRender("Cannot specifically save the **cache** - sorry 🙇");
                return;
            }
            const savedNames = yield this.getSavedStateNames();
            if (savedNames.includes(newStateName)) {
                this.stateView.headerRender(`Cannot create new state **${newStateName}** - already exists`);
            }
            const currSaveName = this.getSaveName();
            if (currSaveName) {
                yield this.saveState({
                    saveName: currSaveName,
                    conversationHistory,
                    trackedFiles,
                    limit,
                });
            }
            else {
                yield this.saveState({
                    saveName: "cache",
                    conversationHistory,
                    trackedFiles,
                    limit,
                });
                this.stateView.renderSavedToCacheBeforeLoad();
            }
            yield this.createEmptyState(newStateName, newStateCallback);
        });
    }
}
exports.StateController = StateController;
