"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());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
    return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (g && (g = 0, op[0] && (_ = 0)), _) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MonitorFunction = exports.MonitorManagerFunction = exports.MonitorMongo = exports.MonitorManager = void 0;
var axios_1 = require("axios");
var monitor_cpu_collection_1 = require("../collections/monitor-cpu.collection");
var monitor_function_collection_1 = require("../collections/monitor-function.collection");
var monitor_memory_collection_1 = require("../collections/monitor-memory.collection");
var monitor_mongo_collection_1 = require("../collections/monitor-mongo.collection");
var resolveio_server_app_1 = require("../resolveio-server-app");
var common_1 = require("../util/common");
var os = require('os');
var MAX_BATCH_SIZE = 8 * 1024 * 1024; // 8MB max for safety
var MonitorManager = /** @class */ (function () {
    function MonitorManager() {
        this._instanceHostname = '';
        this._monitorData = [];
    }
    MonitorManager.create = function () {
        return __awaiter(this, void 0, void 0, function () {
            var monitorManager;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        monitorManager = new MonitorManager();
                        return [4 /*yield*/, monitorManager.initialize()];
                    case 1:
                        _a.sent();
                        return [2 /*return*/, monitorManager];
                }
            });
        });
    };
    MonitorManager.prototype.initialize = function () {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        this._instanceHostname = os.hostname().replace(/\./g, '-');
                        return [4 /*yield*/, this.setupIntervals()];
                    case 1:
                        _a.sent();
                        this.setupEventLoop();
                        return [2 /*return*/];
                }
            });
        });
    };
    MonitorManager.prototype.cpuAverage = function () {
        var totalIdle = 0, totalTick = 0;
        var cpus = os.cpus();
        for (var i = 0, len = cpus.length; i < len; i++) {
            var cpu = cpus[i];
            for (var type in cpu.times) {
                totalTick += cpu.times[type];
            }
            totalIdle += cpu.times.idle;
        }
        return {
            idle: totalIdle / cpus.length,
            total: totalTick / cpus.length
        };
    };
    MonitorManager.prototype.setupIntervals = function () {
        return __awaiter(this, void 0, void 0, function () {
            var processOnlyRuntime, instanceId_1, _a, lastCPU;
            var _this = this;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        processOnlyRuntime = this.isProcessOnlyManagerRuntime();
                        if (!(!processOnlyRuntime
                            &&
                                resolveio_server_app_1.ResolveIOServer.getServerConfig()['ROOT_URL'] !== 'https://resolveio.com'
                            && resolveio_server_app_1.ResolveIOServer.getServerConfig()['ROOT_URL'] !== 'http://localhost:4200')) return [3 /*break*/, 4];
                        _b.label = 1;
                    case 1:
                        _b.trys.push([1, 3, , 4]);
                        return [4 /*yield*/, axios_1.default.get('http://169.254.169.254/latest/meta-data/instance-id')];
                    case 2:
                        instanceId_1 = _b.sent();
                        setInterval(function () { return __awaiter(_this, void 0, void 0, function () {
                            var _a;
                            return __generator(this, function (_b) {
                                switch (_b.label) {
                                    case 0:
                                        _b.trys.push([0, 2, , 3]);
                                        return [4 /*yield*/, axios_1.default.post('https://backend.resolveio.com/api/health', {
                                                type: 'application',
                                                id_aws_instance: instanceId_1.data,
                                                version: typeof process.env.APP_VERSION === 'number'
                                                    ? process.env.APP_VERSION.toString()
                                                    : process.env.APP_VERSION,
                                                version_key: process.env.APP_VERSION_KEY
                                            })];
                                    case 1:
                                        _b.sent();
                                        return [3 /*break*/, 3];
                                    case 2:
                                        _a = _b.sent();
                                        return [3 /*break*/, 3];
                                    case 3: return [2 /*return*/];
                                }
                            });
                        }); }, 10000);
                        return [3 /*break*/, 4];
                    case 3:
                        _a = _b.sent();
                        return [3 /*break*/, 4];
                    case 4:
                        lastCPU = this.cpuAverage();
                        setInterval(function () { return __awaiter(_this, void 0, void 0, function () {
                            var now, endMeasure, idleDifference, totalDifference, percentageCPU, memUsage;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0:
                                        now = new Date();
                                        endMeasure = this.cpuAverage();
                                        idleDifference = endMeasure.idle - lastCPU.idle;
                                        totalDifference = endMeasure.total - lastCPU.total;
                                        percentageCPU = 1 - idleDifference / totalDifference;
                                        if (!!resolveio_server_app_1.ResolveIOServer.shouldWriteLogsOffline()) return [3 /*break*/, 2];
                                        return [4 /*yield*/, monitor_cpu_collection_1.MonitorCPUs.create({
                                                _id: (0, common_1.objectIdHexString)(),
                                                metadata: {
                                                    instance: this._instanceHostname,
                                                    client: resolveio_server_app_1.ResolveIOServer.getServerConfig()['CLIENT_NAME']
                                                },
                                                date: now,
                                                app: percentageCPU,
                                                system: os.loadavg()[0]
                                            })];
                                    case 1:
                                        _a.sent();
                                        return [3 /*break*/, 3];
                                    case 2:
                                        this.pushMonitorData({
                                            type: 'monitor-cpu',
                                            data: {
                                                metadata: {
                                                    instance: this._instanceHostname,
                                                    client: resolveio_server_app_1.ResolveIOServer.getServerConfig()['CLIENT_NAME']
                                                },
                                                date: now,
                                                app: percentageCPU,
                                                system: os.loadavg()[0]
                                            }
                                        });
                                        _a.label = 3;
                                    case 3:
                                        lastCPU = endMeasure;
                                        memUsage = process.memoryUsage();
                                        if (!!resolveio_server_app_1.ResolveIOServer.shouldWriteLogsOffline()) return [3 /*break*/, 5];
                                        return [4 /*yield*/, monitor_memory_collection_1.MonitorMemorys.create({
                                                _id: (0, common_1.objectIdHexString)(),
                                                metadata: {
                                                    instance: this._instanceHostname,
                                                    client: resolveio_server_app_1.ResolveIOServer.getServerConfig()['CLIENT_NAME']
                                                },
                                                date: now,
                                                physical_total: memUsage.heapTotal,
                                                physical_used: memUsage.heapUsed,
                                                physical_free: os.freemem(),
                                                virtual: memUsage.rss,
                                                private: memUsage.external,
                                                physical: os.totalmem()
                                            })];
                                    case 4:
                                        _a.sent();
                                        return [3 /*break*/, 6];
                                    case 5:
                                        this.pushMonitorData({
                                            type: 'monitor-memory',
                                            data: {
                                                metadata: {
                                                    instance: this._instanceHostname,
                                                    client: resolveio_server_app_1.ResolveIOServer.getServerConfig()['CLIENT_NAME']
                                                },
                                                date: now,
                                                physical_total: memUsage.heapTotal,
                                                physical_used: memUsage.heapUsed,
                                                physical_free: os.freemem(),
                                                virtual: memUsage.rss,
                                                private: memUsage.external,
                                                physical: os.totalmem(),
                                                type: 'memory'
                                            }
                                        });
                                        _a.label = 6;
                                    case 6: return [2 /*return*/];
                                }
                            });
                        }); }, 3000);
                        return [2 /*return*/];
                }
            });
        });
    };
    MonitorManager.prototype.isProcessOnlyManagerRuntime = function () {
        var parseFlag = function (value) {
            var normalized = String(value !== null && value !== void 0 ? value : '').trim().toLowerCase();
            return normalized === '1'
                || normalized === 'true'
                || normalized === 'yes'
                || normalized === 'on'
                || normalized === 'enabled';
        };
        return parseFlag(process.env.SUPPORT_CODEX_MANAGER_PROCESS_ONLY)
            || parseFlag(process.env.SUPPORT_AUTO_MANAGER_PROCESS_ONLY)
            || parseFlag(process.env.AI_ASSISTANT_CODEX_MANAGER_PROCESS_ONLY);
    };
    MonitorManager.prototype.addMongoTracker = function (data) {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (!!resolveio_server_app_1.ResolveIOServer.shouldWriteLogsOffline()) return [3 /*break*/, 3];
                        if (!!data.collection.startsWith('monitor-')) return [3 /*break*/, 2];
                        return [4 /*yield*/, monitor_mongo_collection_1.MonitorMongos.create({
                                _id: (0, common_1.objectIdHexString)(),
                                metadata: {
                                    instance: this._instanceHostname,
                                    client: resolveio_server_app_1.ResolveIOServer.getServerConfig()['CLIENT_NAME']
                                },
                                date: new Date(data.date),
                                method: data.method,
                                doc_collection: data.collection,
                                duration: data.duration,
                                query: Buffer.byteLength(data.query, 'utf8') < 15800000
                                    ? data.query
                                    : 'Too Big'
                            })];
                    case 1:
                        _a.sent();
                        _a.label = 2;
                    case 2: return [3 /*break*/, 4];
                    case 3:
                        if (this._instanceHostname) {
                            this.pushMonitorData({
                                type: 'monitor-mongo',
                                data: {
                                    metadata: {
                                        instance: this._instanceHostname,
                                        client: resolveio_server_app_1.ResolveIOServer.getServerConfig()['CLIENT_NAME']
                                    },
                                    date: new Date(data.date),
                                    method: data.method,
                                    doc_collection: data.collection,
                                    duration: data.duration,
                                    query: Buffer.byteLength(data.query, 'utf8') < 15800000
                                        ? data.query
                                        : 'Too Big'
                                }
                            });
                        }
                        _a.label = 4;
                    case 4: return [2 /*return*/];
                }
            });
        });
    };
    MonitorManager.prototype.addFunctionTracker = function (data) {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (typeof (data.data) !== 'string') {
                            data.data = JSON.stringify(data.data);
                        }
                        if (!!resolveio_server_app_1.ResolveIOServer.shouldWriteLogsOffline()) return [3 /*break*/, 2];
                        return [4 /*yield*/, monitor_function_collection_1.MonitorFunctions.create({
                                _id: (0, common_1.objectIdHexString)(),
                                metadata: {
                                    instance: this._instanceHostname,
                                    client: resolveio_server_app_1.ResolveIOServer.getServerConfig()['CLIENT_NAME']
                                },
                                date: new Date(data.startTime),
                                type: data.functionType,
                                name: data.functionName,
                                user: data.user,
                                duration: data.duration,
                                data: Buffer.byteLength(data.data, 'utf8') < 15800000
                                    ? data.data
                                    : 'Too Big'
                            })];
                    case 1:
                        _a.sent();
                        return [3 /*break*/, 3];
                    case 2:
                        if (this._instanceHostname) {
                            this.pushMonitorData({
                                type: 'monitor-function',
                                data: {
                                    metadata: {
                                        instance: this._instanceHostname,
                                        client: resolveio_server_app_1.ResolveIOServer.getServerConfig()['CLIENT_NAME']
                                    },
                                    date: new Date(data.startTime),
                                    type: data.functionType,
                                    name: data.functionName,
                                    user: data.user,
                                    duration: data.duration,
                                    data: Buffer.byteLength(data.data, 'utf8') < 15800000
                                        ? data.data
                                        : 'Too Big'
                                }
                            });
                        }
                        _a.label = 3;
                    case 3: return [2 /*return*/];
                }
            });
        });
    };
    MonitorManager.prototype.pushMonitorData = function (data) {
        this._monitorData.push(data);
        // If data is huge, flush immediately to file
        if (this.estimateBatchSize() >= MAX_BATCH_SIZE) {
            this.flushMonitorData();
        }
    };
    MonitorManager.prototype.estimateBatchSize = function () {
        return this._monitorData.reduce(function (total, item) {
            return total + Buffer.byteLength(JSON.stringify(item));
        }, 0);
    };
    MonitorManager.prototype.setupEventLoop = function () {
        var _this = this;
        // Flush every 2.5 seconds
        setInterval(function () {
            if (_this._monitorData.length > 0) {
                _this.flushMonitorData();
            }
        }, 2500);
    };
    MonitorManager.prototype.flushMonitorData = function () {
        var batch = [];
        var batchSize = 0;
        while (this._monitorData.length > 0 && batchSize < MAX_BATCH_SIZE) {
            var item = this._monitorData.shift();
            var itemSize = Buffer.byteLength(JSON.stringify(item));
            if ((batchSize + itemSize) > MAX_BATCH_SIZE && batch.length > 0) {
                // put the item back for next round
                this._monitorData.unshift(item);
                break;
            }
            batch.push(item);
            batchSize += itemSize;
        }
        try {
            // Now, instead of calling an external HTTP endpoint, we write the batch to disk:
            resolveio_server_app_1.ResolveIOServer.getLocalLogManager().writeLogs(batch);
        }
        catch (error) {
            console.error(new Date(), 'MonitorManager', 'Failed to flush monitor data to file:', error);
        }
    };
    return MonitorManager;
}());
exports.MonitorManager = MonitorManager;
var MonitorMongo = /** @class */ (function () {
    function MonitorMongo() {
        this._startTime = 0;
        this._method = '';
        this._collection = '';
        this._query = '';
    }
    MonitorMongo.create = function (method, collection, query) {
        var monitorMongo = new MonitorMongo();
        monitorMongo.initialize(method, collection, query);
        return monitorMongo;
    };
    MonitorMongo.prototype.initialize = function (method, collection, query) {
        this._startTime = Date.now();
        this._method = method;
        this._collection = collection;
        this._query = query;
    };
    MonitorMongo.prototype.finish = function () {
        return __awaiter(this, void 0, void 0, function () {
            var endTime, mongoMonitor;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        endTime = Date.now();
                        mongoMonitor = {
                            date: new Date(endTime),
                            method: this._method,
                            collection: this._collection,
                            query: this._query,
                            duration: endTime - this._startTime
                        };
                        return [4 /*yield*/, resolveio_server_app_1.ResolveIOServer.getMainServer().getMonitorManager().addMongoTracker(mongoMonitor)];
                    case 1:
                        _a.sent();
                        return [2 /*return*/];
                }
            });
        });
    };
    return MonitorMongo;
}());
exports.MonitorMongo = MonitorMongo;
var MonitorManagerFunction = /** @class */ (function () {
    function MonitorManagerFunction() {
        this._functionCnt = 0;
        this._functions = [];
        this._functionLastCompletedWS = {};
    }
    MonitorManagerFunction.create = function () {
        var monitorManagerFunction = new MonitorManagerFunction();
        monitorManagerFunction.initialize();
        return monitorManagerFunction;
    };
    MonitorManagerFunction.prototype.initialize = function () {
    };
    MonitorManagerFunction.prototype.startMonitorFunction = function (functionType, functionName, user, id_socket, data) {
        var newMonitorFunction = MonitorFunction.create(this._functionCnt++, functionType, functionName, user, id_socket, data);
        this._functions.push(newMonitorFunction);
        return newMonitorFunction.id;
    };
    MonitorManagerFunction.prototype.finishMonitorFunction = function (id) {
        return __awaiter(this, void 0, void 0, function () {
            var monitor;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        monitor = this._functions.find(function (a) { return a.id === id; });
                        if (!monitor) return [3 /*break*/, 2];
                        return [4 /*yield*/, monitor.finish()];
                    case 1:
                        _a.sent();
                        this._functionLastCompleted = monitor;
                        this._functionLastCompletedWS[monitor.id_socket] = monitor;
                        this._functions.splice(this._functions.map(function (a) { return a.id; }).indexOf(id), 1);
                        _a.label = 2;
                    case 2: return [2 /*return*/];
                }
            });
        });
    };
    MonitorManagerFunction.prototype.getActiveMonitorFunctions = function () {
        return this._functions;
    };
    MonitorManagerFunction.prototype.getLastCompletedMonitorFunction = function () {
        return this._functionLastCompleted;
    };
    MonitorManagerFunction.prototype.getLastCompletedMonitorFunctionWS = function () {
        return this._functionLastCompletedWS;
    };
    return MonitorManagerFunction;
}());
exports.MonitorManagerFunction = MonitorManagerFunction;
var MonitorFunction = /** @class */ (function () {
    function MonitorFunction() {
        this._timer = null;
        this.duration = 0;
        this.startTime = null;
        this.endTime = null;
        this.lastTime = null;
        this.id_socket = '';
        this.id = 0;
    }
    MonitorFunction.create = function (id, functionType, functionName, user, id_socket, data) {
        var monitorFunction = new MonitorFunction();
        monitorFunction.initialize(id, functionType, functionName, user, id_socket, data);
        return monitorFunction;
    };
    MonitorFunction.prototype.initialize = function (id, functionType, functionName, user, id_socket, data) {
        var _this = this;
        this.id = id;
        this.startTime = new Date();
        this.functionType = functionType;
        this.functionName = functionName;
        this.user = user;
        this.id_socket = id_socket;
        this.data = data;
        this.lastTime = new Date();
        this._timer = setInterval(function () {
            var diff = Date.now() - _this.lastTime.getTime();
            if (diff > _this.duration) {
                _this.duration = diff;
            }
            _this.lastTime = new Date();
        }, 1000);
    };
    MonitorFunction.prototype.finish = function () {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (this._timer) {
                            clearInterval(this._timer);
                            this._timer = null;
                        }
                        this.endTime = new Date();
                        if (!(this.duration >= 5000)) return [3 /*break*/, 2];
                        // Optional slow function logging or email
                        return [4 /*yield*/, resolveio_server_app_1.ResolveIOServer.getMainServer().getMonitorManager().addFunctionTracker(this)];
                    case 1:
                        // Optional slow function logging or email
                        _a.sent();
                        _a.label = 2;
                    case 2: 
                    // await ResolveIOServer.getMainServer().getMonitorManager().addFunctionTracker(this);
                    return [2 /*return*/, Promise.resolve(true)];
                }
            });
        });
    };
    return MonitorFunction;
}());
exports.MonitorFunction = MonitorFunction;

//# sourceMappingURL=monitor.manager.js.map
