"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@oclif/core");
const chalk_1 = __importDefault(require("chalk"));
const ora_1 = __importDefault(require("ora"));
const nest_app_1 = require("../../lib/nest-app");
const cli_observability_cluster_service_1 = require("../../services/cli-observability-cluster.service");
const cluster_capacity_service_1 = require("../../../../src/modules/infrastructure/clusters/services/cluster-capacity.service");
const context_banner_1 = require("../../lib/context-banner");
class EnvCapacity extends core_1.Command {
    async run() {
        const { flags } = await this.parse(EnvCapacity);
        (0, context_banner_1.printContextBanner)();
        const spinner = (0, ora_1.default)('Computing capacity plan...').start();
        try {
            const app = await (0, nest_app_1.getNestApp)();
            const observabilityService = app.get(cli_observability_cluster_service_1.CliObservabilityClusterService);
            const capacityService = app.get(cluster_capacity_service_1.ClusterCapacityService);
            const cluster = await observabilityService.getObservabilityCluster();
            if (!cluster) {
                spinner.fail('No observability cluster found');
                console.log(chalk_1.default.yellow('\n⚠️  Create a cluster first: ' + chalk_1.default.cyan('flui env create\n')));
                return;
            }
            const plan = await capacityService.getPlan(cluster.id);
            spinner.succeed('Capacity plan computed');
            this.render(plan, flags.top, flags.direction);
        }
        catch (error) {
            spinner.fail('Failed to compute capacity plan');
            console.log(chalk_1.default.red('\n❌ Error:\n'));
            console.log(`   ${error instanceof Error ? error.message : String(error)}\n`);
            this.exit(1);
        }
        finally {
            await (0, nest_app_1.closeNestApp)();
        }
    }
    render(plan, top, direction) {
        console.log(chalk_1.default.cyan('\n📊 Cluster Capacity Plan\n'));
        console.log(`   ${chalk_1.default.bold('Cluster:')}  ${plan.clusterId}`);
        console.log(`   ${chalk_1.default.bold('Provider:')} ${plan.provider}`);
        if (plan.message) {
            console.log(`   ${chalk_1.default.dim(plan.message)}`);
        }
        if (plan.master) {
            const m = plan.master;
            console.log(chalk_1.default.cyan('\n🖥  Master Node\n'));
            console.log(`   ${chalk_1.default.bold('Node:')}        ${m.nodeName}`);
            console.log(`   ${chalk_1.default.bold('Server type:')} ${m.serverType}`);
            console.log(`   ${chalk_1.default.bold('Allocatable:')} ${fmtCpu(m.allocatableCpuMillicores)} CPU, ${fmtMem(m.allocatableMemoryMi)}`);
            console.log(`   ${chalk_1.default.bold('Used:')}        ${fmtCpu(m.usedCpuMillicores)} CPU, ${fmtMem(m.usedMemoryMi)}`);
            const freeColor = m.freeCpuMillicores < 250 || m.freeMemoryMi < 256
                ? chalk_1.default.red
                : chalk_1.default.green;
            const freeLabel = freeColor(`${fmtCpu(m.freeCpuMillicores)} CPU, ${fmtMem(m.freeMemoryMi)}`);
            console.log(`   ${chalk_1.default.bold('Free:')}        ${freeLabel}`);
            if (m.monthlyCostEur) {
                console.log(`   ${chalk_1.default.bold('Cost/month:')}  €${m.monthlyCostEur}`);
            }
        }
        else {
            console.log(chalk_1.default.yellow('\n⚠️  Master node info unavailable.\n'));
        }
        if (plan.storage) {
            console.log(chalk_1.default.cyan('\n💾 Backing Volume\n'));
            console.log(`   ${chalk_1.default.bold('Volume ID:')}    ${plan.storage.volumeId}`);
            console.log(`   ${chalk_1.default.bold('Size:')}         ${plan.storage.sizeGb} GB`);
            if (plan.storage.requestedGb !== undefined) {
                console.log(`   ${chalk_1.default.bold('PVC requested:')} ${plan.storage.requestedGb} GB`);
            }
            if (plan.storage.pricePerGbMonthlyEur) {
                console.log(`   ${chalk_1.default.bold('Price/GB/mo:')}  €${plan.storage.pricePerGbMonthlyEur}`);
            }
        }
        const filtered = direction === 'all'
            ? plan.candidates
            : plan.candidates.filter((c) => c.direction === direction || c.direction === 'current');
        const shown = filtered.slice(0, top);
        console.log(chalk_1.default.cyan('\n📋 Server-type Candidates\n'));
        if (shown.length === 0) {
            console.log(chalk_1.default.dim('   No candidates available.'));
        }
        else {
            const header = [
                pad(chalk_1.default.bold('TYPE'), 14),
                pad(chalk_1.default.bold('DIR'), 11),
                pad(chalk_1.default.bold('CPU'), 5),
                pad(chalk_1.default.bold('RAM'), 8),
                pad(chalk_1.default.bold('DISK'), 7),
                pad(chalk_1.default.bold('€/MONTH'), 10),
                pad(chalk_1.default.bold('Δ/MONTH'), 10),
            ].join('');
            console.log('   ' + header);
            for (const c of shown) {
                console.log('   ' + this.formatRow(c));
            }
            if (filtered.length > shown.length) {
                console.log(chalk_1.default.dim(`\n   … ${filtered.length - shown.length} more (use --top to extend)`));
            }
        }
        console.log(chalk_1.default.dim('\n   Next steps:'));
        console.log(chalk_1.default.dim('     • flui env scale-master --type <name>    (resize master)'));
        console.log(chalk_1.default.dim('     • flui env storage expand --size <NGiB>  (grow backing volume)'));
        console.log('');
    }
    formatRow(c) {
        let dirColor;
        if (c.direction === 'current')
            dirColor = chalk_1.default.cyan;
        else if (c.direction === 'upgrade')
            dirColor = chalk_1.default.yellow;
        else
            dirColor = chalk_1.default.green;
        const deltaNum = Number.parseFloat(c.monthlyDeltaEur);
        let deltaStr;
        if (Number.isNaN(deltaNum))
            deltaStr = 'n/a';
        else if (deltaNum === 0)
            deltaStr = '0.00';
        else
            deltaStr = (deltaNum > 0 ? '+' : '') + deltaNum.toFixed(2);
        let deltaColor;
        if (Number.isNaN(deltaNum) || deltaNum === 0)
            deltaColor = (s) => s;
        else if (deltaNum > 0)
            deltaColor = chalk_1.default.yellow;
        else
            deltaColor = chalk_1.default.green;
        return [
            pad(c.name, 14),
            pad(dirColor(c.direction), 11),
            pad(String(c.cores), 5),
            pad(`${c.memoryGb} GB`, 8),
            pad(`${c.diskGb} GB`, 7),
            pad(`€${c.monthlyCostEur}`, 10),
            pad(deltaColor(deltaStr), 10),
        ].join('');
    }
}
EnvCapacity.description = 'Show master node capacity (allocatable/used/free) and a sorted list of ' +
    'server-type upgrade/downgrade candidates with monthly cost delta. Use ' +
    'this to plan `flui env scale-master` for apps that need dedicated ' +
    'placement on the master (e.g. databases).';
EnvCapacity.examples = [
    '<%= config.bin %> <%= command.id %>',
    '<%= config.bin %> <%= command.id %> --top 5',
    '<%= config.bin %> <%= command.id %> --direction upgrade',
];
EnvCapacity.flags = {
    top: core_1.Flags.integer({
        description: 'Limit candidates shown (default: 10)',
        default: 10,
    }),
    direction: core_1.Flags.string({
        description: 'Filter candidates: upgrade, downgrade, all (default: all)',
        options: ['all', 'upgrade', 'downgrade'],
        default: 'all',
    }),
};
exports.default = EnvCapacity;
function fmtCpu(millicores) {
    return `${(millicores / 1000).toFixed(2)}`;
}
function fmtMem(mi) {
    if (mi >= 1024)
        return `${(mi / 1024).toFixed(2)} GiB`;
    return `${mi} MiB`;
}
function pad(s, width) {
    const visible = s.replaceAll(/\[[0-9;]*m/g, '');
    const gap = Math.max(1, width - visible.length);
    return s + ' '.repeat(gap);
}
