// SPDX-License-Identifier: Apache-2.0
import { VersionRange } from '../../../../../business/utils/version-range.js';
import { Version } from '../../../../../business/utils/version.js';
import { IllegalArgumentError } from '../../../../../business/errors/illegal-argument-error.js';
import { InvalidSchemaVersionError } from '../../api/invalid-schema-version-error.js';
import { getSoloVersion } from '../../../../../../version.js';
import { Templates } from '../../../../../core/templates.js';
export class RemoteConfigV1Migration {
    get range() {
        return VersionRange.fromIntegerVersion(0);
    }
    get version() {
        return new Version(1);
    }
    migrate(source) {
        if (!source) {
            // We should never pass null or undefined to this method, if this happens we should throw an error
            throw new IllegalArgumentError('source must not be null or undefined');
        }
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const clone = structuredClone(source);
        if (clone.schemaVersion && clone.schemaVersion !== 0) {
            // this case should never happen considering the field was not present in version 0 and should default to zero
            // during this migration
            throw new InvalidSchemaVersionError(clone.schemaVersion, 0);
        }
        // Initialize metadata if it doesn't exist
        if (!clone.metadata) {
            clone.metadata = {};
        }
        // remove old typo property
        delete clone.metadata.lastUpdateBy; // changed to lastUpdatedBy
        // Preserve the original metadata and add lastUpdated information
        const originalMetadata = clone.metadata;
        clone.metadata = {
            ...originalMetadata,
            lastUpdatedAt: new Date(),
            lastUpdatedBy: {
                name: 'system',
                hostname: 'migration',
            },
        };
        // pull the versions from the old config, if it isn't set or set as empty,
        // then it will be set to 0.0.0 until an upgrade for the component is performed
        // Normalize version strings by removing 'v' prefix if present
        const normalizeVersion = (version) => {
            if (!version) {
                return '0.0.0';
            }
            //for invalid version such v0.122  convert it to v0.122.0
            if (version.split('.').length === 2) {
                version = version + '.0';
            }
            return version.startsWith('v') ? version.slice(1) : version;
        };
        clone.versions = {
            cli: clone.metadata.soloVersion || getSoloVersion(),
            chart: normalizeVersion(clone.metadata.soloChartVersion),
            consensusNode: normalizeVersion(clone.metadata.hederaPlatformVersion),
            mirrorNodeChart: normalizeVersion(clone.metadata.hederaMirrorNodeChartVersion),
            explorerChart: normalizeVersion(clone.metadata.hederaExplorerChartVersion),
            jsonRpcRelayChart: normalizeVersion(clone.metadata.hederaJsonRpcRelayChartVersion),
            blockNodeChart: '0.0.0',
        };
        // need to keep track of the version of explorer chart since explorer label changed after
        // some specific version.
        const hederaExplorerChartVersion = clone.metadata.hederaExplorerChartVersion;
        // delete the old version structure
        delete clone.metadata.soloVersion;
        delete clone.metadata.soloChartVersion;
        delete clone.metadata.hederaPlatformVersion;
        delete clone.metadata.hederaMirrorNodeChartVersion;
        delete clone.metadata.hederaExplorerChartVersion;
        delete clone.metadata.hederaJsonRpcRelayChartVersion;
        // migrate the clusters
        const clusters = [];
        for (const cluster in clone.clusters) {
            const clusterObject = clone.clusters[cluster];
            clusters.push({
                name: clusterObject.name,
                namespace: clusterObject.namespace,
                deployment: clusterObject.deployment,
                dnsBaseDomain: clusterObject.dnsBaseDomain,
                // change from the old "network-${nodeAlias}-svc.${namespace}.svc" to "network-{nodeAlias}-svc.{namespace}.svc"
                // to align with the default value of the flag dnsConsensusNodePattern
                dnsConsensusNodePattern: clusterObject.dnsConsensusNodePattern.replaceAll('${', '{'),
            });
        }
        // overlay the old cluster references with the new cluster references structure
        clone.clusters = clusters;
        // now stored at the cluster level only
        delete clone.metadata.namespace;
        delete clone.metadata.deploymentName;
        // migrate the components
        clone.state = {
            ledgerPhase: 'initialized',
            consensusNodes: [],
            blockNodes: [],
            mirrorNodes: [],
            relayNodes: [],
            haProxies: [],
            envoyProxies: [],
            explorers: [],
        };
        // Ensure components exists to avoid errors
        if (!clone.components) {
            clone.components = {
                consensusNodes: {},
                haProxies: {},
                envoyProxies: {},
                mirrorNodes: {},
                relays: {},
                mirrorNodeExplorers: {},
            };
        }
        // migrate the consensus nodes
        if (clone.components.consensusNodes) {
            for (const consensusNode in clone.components.consensusNodes) {
                const component = clone.components.consensusNodes[consensusNode];
                clone.state.consensusNodes.push({
                    metadata: {
                        id: component.nodeId,
                        // name: component.name,
                        namespace: component.namespace,
                        cluster: component.cluster,
                        phase: 'started',
                    },
                });
            }
        }
        //migrate haproxies
        if (clone.components.haProxies) {
            for (const haproxy in clone.components.haProxies) {
                const component = clone.components.haProxies[haproxy];
                clone.state.haProxies.push({
                    metadata: {
                        id: Templates.nodeIdFromNodeAlias(component.name),
                        // name: component.name,
                        namespace: component.namespace,
                        cluster: component.cluster,
                        phase: 'started',
                    },
                });
            }
        }
        // migrate envoy proxies
        if (clone.components.envoyProxies) {
            for (const envoyProxy in clone.components.envoyProxies) {
                const component = clone.components.envoyProxies[envoyProxy];
                clone.state.envoyProxies.push({
                    metadata: {
                        id: Templates.nodeIdFromNodeAlias(component.name),
                        // name: component.name,
                        namespace: component.namespace,
                        cluster: component.cluster,
                        phase: 'started',
                    },
                });
            }
        }
        // migrate explorers
        if (clone.components.mirrorNodeExplorers) {
            for (const explorer in clone.components.mirrorNodeExplorers) {
                const component = clone.components.mirrorNodeExplorers[explorer];
                clone.state.explorers.push({
                    version: hederaExplorerChartVersion,
                    metadata: {
                        id: 0,
                        // name: component.name,
                        namespace: component.namespace,
                        cluster: component.cluster,
                        phase: 'started',
                    },
                });
            }
        }
        // migrate mirror nodes
        if (clone.components.mirrorNodes) {
            for (const mirrorNode in clone.components.mirrorNodes) {
                const component = clone.components.mirrorNodes[mirrorNode];
                clone.state.mirrorNodes.push({
                    metadata: {
                        id: 0,
                        // name: component.name,
                        namespace: component.namespace,
                        cluster: component.cluster,
                        phase: 'started',
                    },
                });
            }
        }
        // migrate relay nodes
        if (clone.components.relays) {
            for (const relayNode in clone.components.relays) {
                const component = clone.components.relays[relayNode];
                // convert component.consensusNodeAliases [node1, node2 ] to [1, 2]
                const consensusNodeIds = component.consensusNodeAliases.map((alias) => Templates.nodeIdFromNodeAlias(alias));
                clone.state.relayNodes.push({
                    consensusNodeIds: consensusNodeIds,
                    metadata: {
                        id: 0,
                        // name: component.name,
                        namespace: component.namespace,
                        cluster: component.cluster,
                        phase: 'started',
                    },
                });
            }
        }
        // migrate block node
        if (clone.components.blockNodes) {
            for (const blockNode in clone.components.blockNodes) {
                const component = clone.components.blockNodes[blockNode];
                clone.state.blockNodes.push({
                    metadata: {
                        id: Templates.nodeIdFromNodeAlias(component.name),
                        // name: component.name,
                        namespace: component.namespace,
                        cluster: component.cluster,
                        phase: 'started',
                    },
                });
            }
        }
        // delete the old components structure
        delete clone.components;
        // migrate the history
        clone.history = {};
        clone.history.commands = [];
        // Handle the case when commandHistory is undefined
        if (clone.commandHistory) {
            // Check if commandHistory is an array or an object
            if (Array.isArray(clone.commandHistory)) {
                // If it's an array, push each item to the command array
                for (const historyItem of clone.commandHistory) {
                    clone.history.commands.push(historyItem);
                }
            }
            else if (typeof clone.commandHistory === 'object') {
                // If it's an object, push each key to the command array
                for (const key in clone.commandHistory) {
                    clone.history.commands.push(key);
                }
            }
            // delete the old command history
            delete clone.commandHistory;
        }
        // migrate the last executed command
        if (clone.lastExecutedCommand) {
            clone.history.lastExecutedCommand = clone.lastExecutedCommand;
            // delete the old last executed command
            delete clone.lastExecutedCommand;
        }
        // Set the schema version to the new version
        clone.schemaVersion = this.version.value;
        return clone;
    }
}
//# sourceMappingURL=remote-config-v1-migration.js.map