"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 __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 __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SystemService = void 0;
const api_prisma_1 = require("@hed-hog/api-prisma");
const common_1 = require("@nestjs/common");
const child_process_1 = require("child_process");
const fs = __importStar(require("fs"));
const os = __importStar(require("os"));
const path = __importStar(require("path"));
let SystemService = class SystemService {
    constructor(prismaService) {
        this.prismaService = prismaService;
    }
    async index() {
        const cpus = os.cpus();
        const totalSpeed = cpus.reduce((acc, cpu) => acc + cpu.speed, 0);
        const averageSpeed = totalSpeed / cpus.length;
        return {
            os: {
                name: this.getFriendlyOSName(),
                platform: os.platform(),
                version: os.release(),
                architecture: os.arch(),
                uptime: os.uptime(),
                cpu: this.getCpuInfo(cpus, averageSpeed),
                memory: this.getMemoryInfo(),
                disk: await this.getDiskInfo(),
            },
            modules: await this.getModulesInfo(),
            users: await this.getUsersInfo(),
            database: await this.getDatabaseInfo(),
        };
    }
    getFriendlyOSName() {
        switch (os.platform()) {
            case 'aix':
                return `AIX`;
            case 'darwin':
                return `macOS`;
            case 'freebsd':
                return `FreeBSD`;
            case 'linux':
                return `Linux`;
            case 'openbsd':
                return `OpenBSD`;
            case 'sunos':
                return `SunOS`;
            case 'win32':
                return `Windows`;
            default:
                return `Unknown`;
        }
    }
    async getDatabaseInfo() {
        let connections, size, queriesPerSecond;
        if (process.env.DATABASE_URL.includes('postgres')) {
            [connections, size, queriesPerSecond] = await Promise.all([
                this.prismaService.$queryRaw `SELECT COUNT(*) FROM pg_stat_activity`, // For PostgreSQL
                this.prismaService
                    .$queryRaw `SELECT pg_database_size(current_database())`, // For PostgreSQL
                this.prismaService
                    .$queryRaw `SELECT sum(numbackends) FROM pg_stat_database`, // For PostgreSQL
            ]);
        }
        else if (process.env.DATABASE_URL.includes('mysql')) {
            [connections, size, queriesPerSecond] = await Promise.all([
                this.prismaService
                    .$queryRaw `SHOW STATUS WHERE variable_name = 'Threads_connected'`, // For MySQL
                this.prismaService
                    .$queryRaw `SELECT SUM(data_length + index_length) AS size FROM information_schema.tables WHERE table_schema = DATABASE()`, // For MySQL
                this.prismaService
                    .$queryRaw `SHOW STATUS WHERE variable_name = 'Queries'`, // For MySQL
            ]);
        }
        else {
            throw new Error('Unsupported database type');
        }
        return {
            connections: +String(connections[0].count || connections[0].Value) || 0,
            size: +String(size[0].pg_database_size || size[0].size) || 0,
            queriesPerSecond: +String(queriesPerSecond[0].sum || queriesPerSecond[0].Value) || 0,
        };
    }
    async getUsersInfo() {
        const users = await this.prismaService.user.findMany({
            include: {
                role_user: {
                    where: {
                        role_id: 1,
                    },
                    select: {
                        role_id: true,
                    },
                },
            },
        });
        const activities = await this.prismaService.user_activity.findMany({
            where: {
                created_at: {
                    gte: new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000),
                },
            },
            take: 10,
            orderBy: {
                created_at: 'desc',
            },
            select: {
                created_at: true,
                user: {
                    select: {
                        name: true,
                        id: true,
                    },
                },
            },
        });
        return {
            total: users.length,
            admin: users.filter((user) => user.role_user.length > 0).length,
            active: 0,
            activities,
        };
    }
    async getModulesInfo() {
        const packageJsonPath = path.resolve(process.cwd(), 'package.json');
        return new Promise((resolve, reject) => {
            fs.readFile(packageJsonPath, 'utf8', async (err, data) => {
                if (err) {
                    reject(`Error reading package.json: ${err.message}`);
                    return;
                }
                try {
                    const packageJson = JSON.parse(data);
                    const dependencies = packageJson.dependencies || {};
                    const hedgehogModules = await Promise.all(Object.keys(dependencies)
                        .filter((key) => key.startsWith('@hedhog'))
                        .map(async (key) => {
                        const currentVersion = dependencies[key].replace(/^[\^~]/, '');
                        const latestVersion = await this.getLatestVersion(key);
                        return {
                            name: key,
                            version: dependencies[key],
                            latestVersion,
                            upToDate: currentVersion === latestVersion,
                        };
                    }));
                    resolve(hedgehogModules);
                }
                catch (parseError) {
                    reject(`Error parsing package.json: ${parseError === null || parseError === void 0 ? void 0 : parseError.message}`);
                }
            });
        });
    }
    async getLatestVersion(moduleName) {
        return new Promise((resolve, reject) => {
            (0, child_process_1.exec)(`npm show ${moduleName} version`, (error, stdout, stderr) => {
                if (error) {
                    reject(`Error fetching latest version for ${moduleName}: ${error.message}`);
                    return;
                }
                if (stderr) {
                    reject(`stderr: ${stderr}`);
                    return;
                }
                resolve(stdout.trim());
            });
        });
    }
    getCpuInfo(cpus, averageSpeed) {
        return {
            model: cpus[0].model,
            speed: averageSpeed,
            physicalCores: cpus.length / 2, // Assuming hyper-threading, this gives physical cores
            virtualCores: cpus.length,
        };
    }
    getMemoryInfo() {
        return {
            total: os.totalmem(),
            free: os.freemem(),
        };
    }
    async getDiskInfo() {
        return new Promise((resolve, reject) => {
            const command = this.getDiskCommand();
            if (!command) {
                reject('Unsupported OS');
                return;
            }
            (0, child_process_1.exec)(command, (error, stdout, stderr) => {
                if (error) {
                    reject(`error: ${error.message}`);
                    return;
                }
                if (stderr) {
                    reject(`stderr: ${stderr}`);
                    return;
                }
                const diskInfo = os.platform() === 'win32'
                    ? this.parseWindowsDiskInfo(stdout)
                    : this.parseUnixDiskInfo(stdout);
                resolve(diskInfo.filter((disk) => disk.filesystem !== undefined));
            });
        });
    }
    getDiskCommand() {
        switch (os.platform()) {
            case 'win32':
                if (fs.existsSync('C:\\Windows\\System32\\wbem\\wmic.exe')) {
                    return 'wmic logicaldisk get size,freespace,caption';
                }
                else {
                    return 'powershell -Command "Get-PSDrive -PSProvider FileSystem | Select-Object Name,Used,Free"';
                }
            case 'darwin':
            case 'linux':
                return 'df -h';
            default:
                return null;
        }
    }
    parseWindowsDiskInfo(output) {
        const lines = output.trim().split('\n');
        const result = [];
        for (let i = 1; i < lines.length; i++) {
            const parts = lines[i].trim().split(/\s+/);
            if (parts.length === 3) {
                result.push({
                    filesystem: parts[0].replace(':', ''),
                    size: parseInt(parts[1], 10),
                    free: parseInt(parts[2], 10),
                });
            }
        }
        return result;
    }
    parsedSizeFormated(size) {
        const unit = size.slice(-1).toUpperCase();
        const value = parseFloat(size.slice(0, -1));
        switch (unit) {
            case 'T':
                return value * 1024 ** 4;
            case 'G':
                return value * 1024 ** 3;
            case 'M':
                return value * 1024 ** 2;
            case 'K':
                return value * 1024;
            default:
                return value; // Assume bytes if no unit is provided
        }
    }
    parseUnixDiskInfo(output) {
        const lines = output.trim().split('\n');
        const result = [];
        for (let i = 1; i < lines.length; i++) {
            const parts = lines[i].split(/\s+/);
            if (parts.length >= 6) {
                const size = this.parsedSizeFormated(parts[1]);
                const free = this.parsedSizeFormated(parts[3]);
                result.push({
                    filesystem: parts[0],
                    free,
                    size,
                    mountpoint: parts[5],
                });
            }
        }
        return result;
    }
};
exports.SystemService = SystemService;
exports.SystemService = SystemService = __decorate([
    (0, common_1.Injectable)(),
    __metadata("design:paramtypes", [api_prisma_1.PrismaService])
], SystemService);
//# sourceMappingURL=system.service.js.map