"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 hetzner_provider_service_1 = require("../../../../src/modules/providers/services/hetzner-provider.service");
const cluster_entity_1 = require("../../../../src/modules/infrastructure/clusters/entities/cluster.entity");
const cli_cluster_repository_1 = require("../../lib/repositories/cli-cluster.repository");
const context_banner_1 = require("../../lib/context-banner");
class EnvRestart extends core_1.Command {
    async run() {
        (0, context_banner_1.printContextBanner)();
        let spinner = (0, ora_1.default)('Initializing...').start();
        try {
            // Bootstrap NestJS and get services
            const app = await (0, nest_app_1.getNestApp)();
            spinner.succeed('Initialized');
            console.log(chalk_1.default.cyan('\n🔄 Restarting Observability Cluster\n'));
            spinner = (0, ora_1.default)('Finding cluster...').start();
            const observabilityService = app.get(cli_observability_cluster_service_1.CliObservabilityClusterService);
            // Get observability cluster
            const cluster = await observabilityService.getObservabilityCluster();
            if (!cluster) {
                spinner.fail('No observability cluster found');
                console.log(chalk_1.default.yellow('\n⚠️  No observability cluster exists.\n'));
                console.log(`Create one with: ${chalk_1.default.cyan('flui env create')}\n`);
                return;
            }
            if (!cluster.nodes || cluster.nodes.length === 0) {
                spinner.fail('No cluster nodes found');
                console.log(chalk_1.default.yellow('\n⚠️  Cluster has no nodes.\n'));
                return;
            }
            spinner.succeed(`Found cluster with ${cluster.nodes.length} node(s)`);
            // Check if cluster is already running
            if (cluster.status === cluster_entity_1.ClusterStatus.READY) {
                console.log(chalk_1.default.yellow('\n⚠️  Cluster is already running.\n'));
                console.log(`   Check status with: ${chalk_1.default.cyan('flui env status')}\n`);
                return;
            }
            // Get Hetzner provider (we need the concrete type for poweron)
            const hetznerProvider = app.get(hetzner_provider_service_1.HetznerProviderService);
            // Check current server states
            let allRunning = true;
            const serverStates = [];
            spinner = (0, ora_1.default)('Checking server states...').start();
            for (const node of cluster.nodes) {
                try {
                    const serverDto = await hetznerProvider.getServerDetailsAsDto(node.providerResourceId);
                    if (serverDto) {
                        serverStates.push({
                            name: node.serverName,
                            id: node.providerResourceId,
                            status: serverDto.status,
                        });
                        if (serverDto.status !== 'running') {
                            allRunning = false;
                        }
                    }
                }
                catch {
                    spinner.warn(`Could not check status for ${node.serverName}`);
                }
            }
            spinner.succeed('Server states checked');
            if (allRunning) {
                console.log(chalk_1.default.yellow('\n⚠️  All cluster servers are already running.\n'));
                // Update cluster status to READY
                spinner = (0, ora_1.default)('Updating cluster status...').start();
                const clusterRepository = app.get(cli_cluster_repository_1.CliClusterRepository);
                cluster.status = cluster_entity_1.ClusterStatus.READY;
                await clusterRepository.save(cluster);
                spinner.succeed('Cluster status updated to READY');
                console.log(`\n   Check status with: ${chalk_1.default.cyan('flui env status')}\n`);
                return;
            }
            // Show cluster info
            console.log(chalk_1.default.cyan('\n📋 Cluster Information:\n'));
            console.log(`   ${chalk_1.default.bold('Name:')}   ${cluster.name}`);
            console.log(`   ${chalk_1.default.bold('ID:')}     ${cluster.id}`);
            console.log(`   ${chalk_1.default.bold('Nodes:')}  ${cluster.nodes.length}`);
            console.log(`   ${chalk_1.default.bold('Region:')} ${cluster.region}\n`);
            // Start all stopped servers
            let startedCount = 0;
            for (const state of serverStates) {
                if (state.status === 'off') {
                    spinner = (0, ora_1.default)(`Powering on ${state.name}...`).start();
                    try {
                        await hetznerProvider.powerOnServer(state.id);
                        spinner.succeed(`${state.name} powered on`);
                        startedCount++;
                    }
                    catch (error) {
                        spinner.fail(`Failed to power on ${state.name}: ${error.message}`);
                    }
                }
                else {
                    console.log(chalk_1.default.dim(`   ${state.name} - already running`));
                }
            }
            if (startedCount > 0) {
                console.log(chalk_1.default.green(`\n✅ Successfully started ${startedCount} server(s)\n`));
                // Wait for servers to become ready
                spinner = (0, ora_1.default)('Waiting for servers to boot...').start();
                await this.sleep(10000); // Wait 10 seconds for servers to boot
                spinner.succeed('Servers should be booting');
                // Wait for K3s services to be ready
                console.log(chalk_1.default.cyan('\n⏳ Waiting for services to be ready...\n'));
                console.log(chalk_1.default.dim('   This may take 1-2 minutes as K3s restarts...\n'));
                const maxAttempts = 24; // 2 minutes with 5 second intervals
                let servicesReady = false;
                for (let attempt = 1; attempt <= maxAttempts; attempt++) {
                    spinner = (0, ora_1.default)(`Checking services (attempt ${attempt}/${maxAttempts})...`).start();
                    try {
                        const servicesHealth = await observabilityService.checkObservabilityServices(cluster.masterIpAddress, cluster.nipHostnameToken);
                        const allHealthy = servicesHealth.prometheus === 'healthy' &&
                            servicesHealth.grafana === 'healthy' &&
                            servicesHealth.loki === 'healthy';
                        if (allHealthy) {
                            spinner.succeed('All services are ready!');
                            servicesReady = true;
                            break;
                        }
                        else {
                            spinner.text = `Services not ready yet (${attempt}/${maxAttempts})...`;
                            spinner.color = 'yellow';
                            await this.sleep(5000);
                            spinner.stop();
                        }
                    }
                    catch {
                        spinner.stop();
                        if (attempt < maxAttempts) {
                            await this.sleep(5000);
                        }
                    }
                }
                if (!servicesReady) {
                    console.log(chalk_1.default.yellow('\n⚠️  Services are taking longer than expected to start.\n'));
                    console.log(chalk_1.default.dim('   They may still be initializing. Check again with:'));
                    console.log(`   ${chalk_1.default.cyan('flui env status')}\n`);
                }
                // Update cluster status to READY
                spinner = (0, ora_1.default)('Updating cluster status...').start();
                const clusterRepository = app.get(cli_cluster_repository_1.CliClusterRepository);
                cluster.status = cluster_entity_1.ClusterStatus.READY;
                await clusterRepository.save(cluster);
                spinner.succeed('Cluster status updated to READY');
            }
            console.log(chalk_1.default.cyan('\n💰 Cost Information:\n'));
            console.log(`   ${chalk_1.default.bold('Current cost:')} ~${7.5 * cluster.nodes.length}€/month (running)`);
            console.log(`   ${chalk_1.default.dim('To save costs when not in use:')}`);
            console.log(`   ${chalk_1.default.cyan('flui env stop')}\n`);
            console.log(chalk_1.default.cyan('\n🔗 Next Steps:\n'));
            console.log(`   Check cluster status: ${chalk_1.default.cyan('flui env status')}`);
            console.log(`   View endpoints and credentials\n`);
        }
        catch (error) {
            spinner.fail('Failed to restart environment');
            console.log(chalk_1.default.red('\n❌ Error:\n'));
            if (error instanceof Error) {
                console.log(`   ${error.message}\n`);
            }
            else {
                console.log(`   ${String(error)}\n`);
            }
            this.exit(1);
        }
        finally {
            await (0, nest_app_1.closeNestApp)();
        }
    }
    /**
     * Sleep helper
     */
    sleep(ms) {
        return new Promise((resolve) => setTimeout(resolve, ms));
    }
}
EnvRestart.description = 'Restart stopped observability cluster servers';
EnvRestart.examples = ['<%= config.bin %> <%= command.id %>'];
exports.default = EnvRestart;
