"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 cli_endpoint_resolver_service_1 = require("../../services/cli-endpoint-resolver.service");
const cluster_entity_1 = require("../../../../src/modules/infrastructure/clusters/entities/cluster.entity");
const context_banner_1 = require("../../lib/context-banner");
const config_storage_1 = require("../../lib/config-storage");
const nip_base_domain_util_1 = require("../../lib/nip-base-domain.util");
class EnvStatus extends core_1.Command {
    async run() {
        (0, context_banner_1.printContextBanner)();
        let spinner = (0, ora_1.default)('Checking cluster status...').start();
        try {
            const app = await (0, nest_app_1.getNestApp)();
            const observabilityService = app.get(cli_observability_cluster_service_1.CliObservabilityClusterService);
            const resolver = app.get(cli_endpoint_resolver_service_1.CliEndpointResolverService);
            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(chalk_1.default.dim('Create one with:'));
                console.log(`   ${chalk_1.default.cyan('flui env create')}\n`);
                return;
            }
            spinner.succeed('Cluster found');
            if (cluster.masterIpAddress) {
                const storage = new config_storage_1.ConfigStorage();
                const derived = `https://api.${(0, nip_base_domain_util_1.buildNipBaseDomain)(cluster.masterIpAddress, cluster.nipHostnameToken)}/api/v1`;
                if (storage.getApiUrl() !== derived) {
                    storage.saveApiUrl(derived);
                }
            }
            console.log(chalk_1.default.cyan('\n📋 Observability Cluster Status\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('Status:')}     ${this.formatStatus(cluster.status)}`);
            console.log(`   ${chalk_1.default.bold('Provider:')}   ${cluster.provider}`);
            console.log(`   ${chalk_1.default.bold('Region:')}     ${cluster.region}`);
            console.log(`   ${chalk_1.default.bold('Master IP:')}  ${cluster.masterIpAddress || 'N/A'}`);
            console.log(`   ${chalk_1.default.bold('Nodes:')}      ${cluster.nodeCount}`);
            console.log(`   ${chalk_1.default.bold('Created:')}    ${cluster.createdAt.toLocaleString()}`);
            // Get nodes info
            if (cluster.nodes && cluster.nodes.length > 0) {
                console.log(chalk_1.default.cyan('\n🖥️  Cluster Nodes:\n'));
                for (const node of cluster.nodes) {
                    const marker = node.nodeType === 'master' ? chalk_1.default.cyan('●') : chalk_1.default.dim('●');
                    console.log(`   ${marker} ${chalk_1.default.bold(node.serverName)}`);
                    console.log(`      Type: ${node.nodeType}`);
                    console.log(`      IP: ${node.ipAddress || 'N/A'}`);
                    console.log(`      Status: ${this.formatStatus(node.status)}`);
                }
            }
            if (cluster.status === cluster_entity_1.ClusterStatus.READY && cluster.masterIpAddress) {
                spinner = await this.renderObservabilityHealth(observabilityService, cluster.masterIpAddress, cluster.nipHostnameToken, spinner);
            }
            else if (cluster.status === cluster_entity_1.ClusterStatus.STOPPED) {
                console.log(chalk_1.default.cyan('\n💤 Cluster Status:\n'));
                console.log(`   ${chalk_1.default.yellow('Cluster is currently stopped to save costs')}`);
                console.log(`   ${chalk_1.default.dim('To restart it, run:')}`);
                console.log(`   ${chalk_1.default.cyan('flui env restart')}\n`);
            }
            if (cluster.status === cluster_entity_1.ClusterStatus.READY && cluster.masterIpAddress) {
                spinner = await this.renderEndpointsAndCredentials(resolver, cluster, spinner);
                console.log(chalk_1.default.bold('\n   To retrieve your credentials, run:'));
                console.log(chalk_1.default.cyan('   flui env credentials\n'));
            }
            console.log('');
        }
        catch (error) {
            spinner.fail('Failed to check cluster status');
            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)();
        }
    }
    async renderObservabilityHealth(observabilityService, masterIp, nipHostnameToken, initialSpinner) {
        initialSpinner.stop();
        const spinner = (0, ora_1.default)('Checking observability services...').start();
        try {
            const servicesHealth = await observabilityService.checkObservabilityServices(masterIp, nipHostnameToken);
            spinner.succeed('Services health checked');
            console.log(chalk_1.default.cyan('\n📊 Observability Services Status:\n'));
            const note = chalk_1.default.dim('(deployment ready)');
            const rows = [
                ['Metrics:   ', servicesHealth.prometheus],
                ['Grafana:   ', servicesHealth.grafana],
                ['Loki:      ', servicesHealth.loki],
                ['Postgres:  ', servicesHealth.postgres],
                ['Redis:     ', servicesHealth.redis],
                ['Flui API:  ', servicesHealth.fluiApi],
                ['Dashboard: ', servicesHealth.fluiWeb],
            ];
            for (const [label, status] of rows) {
                const icon = status === 'healthy' ? '✅' : '❌';
                const color = status === 'healthy' ? chalk_1.default.green : chalk_1.default.red;
                console.log(`   ${icon} ${chalk_1.default.bold(label)} ${color(status)} ${note}`);
            }
        }
        catch (error) {
            spinner.warn('Could not check services health');
            console.log(chalk_1.default.dim(`   ${error.message}\n`));
        }
        return spinner;
    }
    async renderEndpointsAndCredentials(resolver, cluster, initialSpinner) {
        initialSpinner.stop();
        const spinner = (0, ora_1.default)('Resolving effective endpoints via SSH...').start();
        try {
            const endpoints = await resolver.resolveEndpoints(cluster.masterIpAddress, cluster.nipHostnameToken);
            spinner.succeed('Endpoints resolved');
            this.renderEndpoints(endpoints);
            const passwords = cluster.metadata?.observabilityStack?.passwords;
            if (passwords) {
                console.log(chalk_1.default.cyan('\n🔑 Credentials:\n'));
                console.log(`   ${chalk_1.default.bold('Grafana:')}    admin / ${chalk_1.default.yellow(passwords.grafana)}`);
                console.log(`   ${chalk_1.default.bold('PostgreSQL:')} fluicloud / ${chalk_1.default.yellow(passwords.postgres)}`);
                console.log(`   ${chalk_1.default.bold('Redis:')}      ${chalk_1.default.yellow(passwords.redis)}`);
            }
        }
        catch {
            spinner.warn('Could not fetch all endpoints');
        }
        return spinner;
    }
    formatStatus(status) {
        const statusColors = {
            creating: chalk_1.default.yellow,
            ready: chalk_1.default.green,
            scaling: chalk_1.default.blue,
            stopped: chalk_1.default.yellow,
            error: chalk_1.default.red,
            deleting: chalk_1.default.red,
            deleted: chalk_1.default.dim,
        };
        const color = statusColors[status.toLowerCase()] || chalk_1.default.white;
        return color(status.toUpperCase());
    }
    renderEndpoints(endpoints) {
        console.log(chalk_1.default.cyan('\n🔗 Service Endpoints:\n'));
        console.log(`   ${chalk_1.default.bold('Auth mode:')} ${chalk_1.default.blue(endpoints.authMode)}`);
        const rows = [
            ['Flui API  ', endpoints.fluiApi],
            ['Dashboard ', endpoints.fluiWeb],
            ['Zitadel   ', endpoints.zitadel],
            ['Grafana   ', endpoints.grafana],
            ['Prometheus', endpoints.prometheus],
            ['Loki      ', endpoints.loki],
        ];
        for (const [label, info] of rows) {
            if (typeof info !== 'object' ||
                info === null ||
                !('effectiveUrl' in info))
                continue;
            const marker = info.synced ? chalk_1.default.green('●') : chalk_1.default.dim('○');
            const url = info.synced
                ? chalk_1.default.blue(info.effectiveUrl)
                : chalk_1.default.dim(info.effectiveUrl);
            const suffix = info.synced
                ? chalk_1.default.dim(' (custom domain)')
                : chalk_1.default.dim(' (in-cluster only)');
            console.log(`   ${marker} ${chalk_1.default.bold(label)} ${url}${suffix}`);
        }
    }
}
EnvStatus.description = 'Check observability cluster status';
EnvStatus.examples = ['<%= config.bin %> <%= command.id %>'];
exports.default = EnvStatus;
