// SPDX-License-Identifier: Apache-2.0
import { BaseCommandTest } from './base-command-test.js';
import { main } from '../../../../src/index.js';
import { Flags } from '../../../../src/commands/flags.js';
import { InjectTokens } from '../../../../src/core/dependency-injection/inject-tokens.js';
import { expect } from 'chai';
import { container } from 'tsyringe-neo';
import { DeploymentCommandDefinition } from '../../../../src/commands/command-definitions/deployment-command-definition.js';
import fs from 'node:fs/promises';
import yaml from 'yaml';
import { PathEx } from '../../../../src/business/utils/path-ex.js';
export class DeploymentTest extends BaseCommandTest {
    static soloDeploymentCreateArgv(testName, deployment, namespace, realm, shard) {
        const { newArgv, optionFromFlag, argvPushGlobalFlags } = DeploymentTest;
        const argv = newArgv();
        argv.push(DeploymentCommandDefinition.COMMAND_NAME, DeploymentCommandDefinition.CONFIG_SUBCOMMAND_NAME, DeploymentCommandDefinition.CONFIG_CREATE, optionFromFlag(Flags.deployment), deployment, optionFromFlag(Flags.namespace), namespace.name, optionFromFlag(Flags.realm), String(realm), optionFromFlag(Flags.shard), String(shard));
        argvPushGlobalFlags(argv, testName);
        return argv;
    }
    static create(options) {
        const { testName, testLogger, deployment, namespace, realm, shard } = options;
        const { soloDeploymentCreateArgv } = DeploymentTest;
        it(`${testName}: solo deployment config create`, async () => {
            testLogger.info(`${testName}: beginning solo deployment config create`);
            await main(soloDeploymentCreateArgv(testName, deployment, namespace, realm, shard));
            // TODO check that the deployment was created
            testLogger.info(`${testName}: finished solo deployment config create`);
        });
    }
    static soloDeploymentAddClusterArgv(testName, deployment, clusterReference, numberOfNodes) {
        const { newArgv, optionFromFlag, argvPushGlobalFlags } = DeploymentTest;
        const argv = newArgv();
        argv.push(DeploymentCommandDefinition.COMMAND_NAME, DeploymentCommandDefinition.CLUSTER_SUBCOMMAND_NAME, DeploymentCommandDefinition.CLUSTER_ATTACH, optionFromFlag(Flags.deployment), deployment, optionFromFlag(Flags.clusterRef), clusterReference, optionFromFlag(Flags.numberOfConsensusNodes), numberOfNodes.toString());
        argvPushGlobalFlags(argv, testName);
        return argv;
    }
    static addCluster(options) {
        const { testName, testLogger, deployment, clusterReferenceNameArray, consensusNodesCount } = options;
        const { soloDeploymentAddClusterArgv } = DeploymentTest;
        it(`${testName}: solo deployment cluster attach`, async () => {
            testLogger.info(`${testName}: beginning solo deployment cluster attach`);
            // Compute distribution
            const clusterCount = clusterReferenceNameArray.length;
            const base = Math.floor(consensusNodesCount / clusterCount);
            const remainder = consensusNodesCount % clusterCount;
            const nodeCountsPerCluster = clusterReferenceNameArray.map((_, index) => index < remainder ? base + 1 : base);
            // Now attach clusters with correct node count
            for (const [index, element] of clusterReferenceNameArray.entries()) {
                const nodeCount = nodeCountsPerCluster[index];
                await main(soloDeploymentAddClusterArgv(testName, deployment, element, nodeCount));
            }
            const remoteConfig = container.resolve(InjectTokens.RemoteConfigRuntimeState);
            expect(remoteConfig.isLoaded(), 'remote config manager should be loaded').to.be.true;
            const consensusNodes = remoteConfig.configuration.components.state.consensusNodes;
            expect(Object.entries(consensusNodes).length, `consensus node count should be ${consensusNodesCount}`).to.equal(consensusNodesCount);
            for (const [index, element] of clusterReferenceNameArray.entries()) {
                expect(consensusNodes[index].metadata.cluster).to.equal(element);
            }
            testLogger.info(`${testName}: finished solo deployment cluster attach`);
        });
    }
    static soloDeploymentDiagnosticsLogsArgv(deployment) {
        const { newArgv, optionFromFlag } = DeploymentTest;
        const argv = newArgv();
        argv.push(DeploymentCommandDefinition.COMMAND_NAME, DeploymentCommandDefinition.DIAGNOSTICS_SUBCOMMAND_NAME, DeploymentCommandDefinition.DIAGNOSTICS_LOGS, optionFromFlag(Flags.deployment), deployment);
        return argv;
    }
    static soloDeploymentConfigCreateArgv(deployment, namespace) {
        const { newArgv, optionFromFlag } = DeploymentTest;
        const argv = newArgv();
        argv.push(DeploymentCommandDefinition.COMMAND_NAME, DeploymentCommandDefinition.CONFIG_SUBCOMMAND_NAME, DeploymentCommandDefinition.CONFIG_CREATE, optionFromFlag(Flags.deployment), deployment, optionFromFlag(Flags.namespace), namespace.name);
        return argv;
    }
    static soloDeploymentClusterAttachArgv(deployment, clusterReference, consensusNodesCount) {
        const { newArgv, optionFromFlag } = DeploymentTest;
        const argv = newArgv();
        argv.push(DeploymentCommandDefinition.COMMAND_NAME, DeploymentCommandDefinition.CLUSTER_SUBCOMMAND_NAME, DeploymentCommandDefinition.CLUSTER_ATTACH, optionFromFlag(Flags.clusterRef), clusterReference, optionFromFlag(Flags.deployment), deployment, optionFromFlag(Flags.numberOfConsensusNodes), consensusNodesCount.toString());
        return argv;
    }
    static soloDeploymentConfigListArgv(testName, clusterReference) {
        const { newArgv, optionFromFlag, argvPushGlobalFlags } = DeploymentTest;
        const argv = newArgv();
        argv.push(DeploymentCommandDefinition.COMMAND_NAME, DeploymentCommandDefinition.CONFIG_SUBCOMMAND_NAME, DeploymentCommandDefinition.CONFIG_LIST);
        if (clusterReference) {
            argv.push(optionFromFlag(Flags.clusterRef), clusterReference);
        }
        argvPushGlobalFlags(argv, testName);
        return argv;
    }
    /**
     * Lists all local deployment configurations or deployments in a specific cluster.
     * Tests both scenarios:
     * 1. Without cluster-ref: Lists all deployments from local configuration
     * 2. With cluster-ref: Lists deployments from the specified Kubernetes cluster
     */
    static listDeployments(options) {
        const { testName, testLogger, clusterReferenceNameArray } = options;
        const { soloDeploymentConfigListArgv } = DeploymentTest;
        it(`${testName}: solo deployment config list (without cluster-ref)`, async () => {
            testLogger.info(`${testName}: beginning solo deployment config list without cluster-ref`);
            await main(soloDeploymentConfigListArgv(testName));
            testLogger.info(`${testName}: finished solo deployment config list without cluster-ref`);
        });
        if (clusterReferenceNameArray && clusterReferenceNameArray.length > 0) {
            it(`${testName}: solo deployment config list (with cluster-ref)`, async () => {
                testLogger.info(`${testName}: beginning solo deployment config list with cluster-ref`);
                await main(soloDeploymentConfigListArgv(testName, clusterReferenceNameArray[0]));
                testLogger.info(`${testName}: finished solo deployment config list with cluster-ref`);
            });
        }
    }
    static soloDeploymentConfigInfoArgv(testName, deployment) {
        const { newArgv, optionFromFlag, argvPushGlobalFlags } = DeploymentTest;
        const argv = newArgv();
        argv.push(DeploymentCommandDefinition.COMMAND_NAME, DeploymentCommandDefinition.CONFIG_SUBCOMMAND_NAME, DeploymentCommandDefinition.CONFIG_INFO, optionFromFlag(Flags.deployment), deployment);
        argvPushGlobalFlags(argv, testName);
        return argv;
    }
    static info(options) {
        const { testName, testLogger, deployment } = options;
        const { soloDeploymentConfigInfoArgv } = DeploymentTest;
        it(`${testName}: solo deployment config info`, async () => {
            testLogger.info(`${testName}: beginning solo deployment config info`);
            await main(soloDeploymentConfigInfoArgv(testName, deployment));
            testLogger.info(`${testName}: finished solo deployment config info`);
        });
    }
    static verifyDeploymentConfigInfo(options) {
        const { testName, testLogger, deployment, namespace } = options;
        const { soloDeploymentConfigInfoArgv, runMainAndCaptureOutputToJson } = DeploymentTest;
        it(`${testName}: verify deployment config info output`, async () => {
            testLogger.info(`${testName}: beginning deployment config info output verification`);
            const { stdout, outputFilePath } = await runMainAndCaptureOutputToJson(soloDeploymentConfigInfoArgv(testName, deployment), {
                testName,
                outputFileName: 'deployment-config-info-output.json',
                metadata: {
                    command: 'deployment config info',
                    deployment,
                    namespace: namespace.name,
                },
            });
            expect(stdout).to.contain('Deployment:');
            expect(stdout).to.contain(deployment);
            expect(stdout).to.contain('Namespace:');
            expect(stdout).to.contain(namespace.name);
            testLogger.info(`${testName}: deployment config info output saved to ${outputFilePath}`);
            testLogger.info(`${testName}: finished deployment config info output verification`);
        });
    }
    static soloDeploymentConfigPortsArgv(testName, deployment, clusterReference, output, cacheDirectory) {
        const { newArgv, optionFromFlag, argvPushGlobalFlags } = DeploymentTest;
        const argv = newArgv();
        argv.push(DeploymentCommandDefinition.COMMAND_NAME, DeploymentCommandDefinition.CONFIG_SUBCOMMAND_NAME, DeploymentCommandDefinition.CONFIG_PORTS, optionFromFlag(Flags.deployment), deployment, optionFromFlag(Flags.clusterRef), clusterReference, optionFromFlag(Flags.cacheDir), cacheDirectory);
        if (output) {
            argv.push(optionFromFlag(Flags.output), output);
        }
        argvPushGlobalFlags(argv, testName);
        return argv;
    }
    static verifyDeploymentConfigPorts(options) {
        const { testName, testLogger, deployment, clusterReferenceNameArray, namespace, testCacheDirectory } = options;
        const { soloDeploymentConfigPortsArgv, runMainAndCaptureOutputToJson, assertPortsFile } = DeploymentTest;
        it(`${testName}: verify deployment config ports output`, async () => {
            testLogger.info(`${testName}: beginning deployment config ports output verification`);
            const clusterReference = clusterReferenceNameArray[0];
            const outputDirectory = PathEx.join(testCacheDirectory, 'output');
            const jsonPortsFile = PathEx.join(outputDirectory, 'forwarded-ports.json');
            const yamlPortsFile = PathEx.join(outputDirectory, 'forwarded-ports.yaml');
            await fs.rm(jsonPortsFile, { force: true });
            await fs.rm(yamlPortsFile, { force: true });
            console.log(options);
            const wideResult = await runMainAndCaptureOutputToJson(soloDeploymentConfigPortsArgv(testName, deployment, clusterReference, 'wide', testCacheDirectory), {
                testName,
                outputFileName: 'deployment-config-ports-wide-output.json',
                metadata: {
                    command: 'deployment config ports',
                    deployment,
                    namespace: namespace.name,
                    clusterReference,
                    output: 'wide',
                },
            });
            expect(wideResult.stdout).to.contain('Port-forwards for deployment');
            expect(wideResult.stdout).to.contain(deployment);
            expect(wideResult.stdout).to.contain('Cluster:');
            expect(wideResult.stdout).to.contain(clusterReference);
            expect(wideResult.stdout).to.contain('Namespace:');
            expect(wideResult.stdout).to.contain('Consensus node gRPC');
            expect(wideResult.stdout).to.contain('Mirror node REST');
            expect(wideResult.stdout).to.contain('JSON-RPC relay');
            expect(wideResult.stdout).to.contain('Explorer');
            const jsonResult = await runMainAndCaptureOutputToJson(soloDeploymentConfigPortsArgv(testName, deployment, clusterReference, 'json', testCacheDirectory), {
                testName,
                outputFileName: 'deployment-config-ports-json-output.json',
                metadata: {
                    command: 'deployment config ports',
                    deployment,
                    namespace: namespace.name,
                    clusterReference,
                    output: 'json',
                },
            });
            expect(jsonResult.stdout).to.contain('"deployment"');
            expect(jsonResult.stdout).to.contain(deployment);
            expect(jsonResult.stdout).to.contain('"clusterReference"');
            expect(jsonResult.stdout).to.contain(clusterReference);
            expect(jsonResult.stdout).to.contain('"namespace"');
            expect(jsonResult.stdout).to.contain('"services"');
            expect(jsonResult.stdout).to.contain('"consensusNodeGrpc"');
            expect(jsonResult.stdout).to.contain('"mirrorNodeRest"');
            expect(jsonResult.stdout).to.contain('"jsonRpcRelay"');
            expect(jsonResult.stdout).to.contain('"explorer"');
            expect(jsonResult.stdout).to.contain('"blockNode"');
            await assertPortsFile(jsonPortsFile, 'json', deployment, clusterReference);
            const yamlResult = await runMainAndCaptureOutputToJson(soloDeploymentConfigPortsArgv(testName, deployment, clusterReference, 'yaml', testCacheDirectory), {
                testName,
                outputFileName: 'deployment-config-ports-yaml-output.json',
                metadata: {
                    command: 'deployment config ports',
                    deployment,
                    namespace: namespace.name,
                    clusterReference,
                    output: 'yaml',
                },
            });
            expect(yamlResult.stdout).to.contain('deployment:');
            expect(yamlResult.stdout).to.contain(deployment);
            expect(yamlResult.stdout).to.contain('clusterReference:');
            expect(yamlResult.stdout).to.contain(clusterReference);
            expect(yamlResult.stdout).to.contain('namespace:');
            expect(yamlResult.stdout).to.contain('services:');
            expect(yamlResult.stdout).to.contain('consensusNodeGrpc:');
            expect(yamlResult.stdout).to.contain('mirrorNodeRest:');
            expect(yamlResult.stdout).to.contain('jsonRpcRelay:');
            expect(yamlResult.stdout).to.contain('explorer:');
            expect(yamlResult.stdout).to.contain('blockNode:');
            await assertPortsFile(yamlPortsFile, 'yaml', deployment, clusterReference);
            testLogger.info(`${testName}: deployment config ports wide output saved to ${wideResult.outputFilePath}`);
            testLogger.info(`${testName}: deployment config ports json output saved to ${jsonResult.outputFilePath}`);
            testLogger.info(`${testName}: deployment config ports yaml output saved to ${yamlResult.outputFilePath}`);
            testLogger.info(`${testName}: finished deployment config ports output verification`);
        });
    }
    static async assertPortsFile(filePath, format, deployment, clusterReference) {
        const raw = await fs.readFile(filePath, 'utf8');
        const parsed = format === 'json' ? JSON.parse(raw) : yaml.parse(raw);
        expect(parsed.deployment).to.equal(deployment);
        expect(parsed.clusterReference).to.equal(clusterReference);
        expect(parsed.services).to.be.an('object');
        expect(parsed.services).to.have.property('consensusNodeGrpc').that.is.an('array');
        expect(parsed.services).to.have.property('mirrorNodeRest').that.is.an('array');
        expect(parsed.services).to.have.property('jsonRpcRelay').that.is.an('array');
        expect(parsed.services).to.have.property('explorer').that.is.an('array');
        expect(parsed.services).to.have.property('blockNode').that.is.an('array');
    }
}
//# sourceMappingURL=deployment-test.js.map