// SPDX-License-Identifier: Apache-2.0
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
var RemoteConfigValidator_1;
import * as constants from '../../constants.js';
import { SoloError } from '../../errors/solo-error.js';
import { Templates } from '../../templates.js';
import { DeploymentPhase } from '../../../data/schema/model/remote/deployment-phase.js';
import { inject, injectable } from 'tsyringe-neo';
import { patchInject } from '../../dependency-injection/container-helper.js';
import { InjectTokens } from '../../dependency-injection/inject-tokens.js';
import { ExplorerStateSchema } from '../../../data/schema/model/remote/state/explorer-state-schema.js';
import { SemVer } from 'semver';
import { EXPLORER_OLD_VERSION_BEFORE_LABEL_CHANGE } from '../../../../version.js';
/**
 * Static class is used to validate that components in the remote config
 * are present in the kubernetes cluster, and throw errors if there is mismatch.
 */
let RemoteConfigValidator = class RemoteConfigValidator {
    static { RemoteConfigValidator_1 = this; }
    k8Factory;
    localConfig;
    constructor(k8Factory, localConfig) {
        this.k8Factory = k8Factory;
        this.localConfig = localConfig;
        this.k8Factory = patchInject(k8Factory, InjectTokens.K8Factory, this.constructor.name);
        this.localConfig = patchInject(localConfig, InjectTokens.LocalConfigRuntimeState, this.constructor.name);
    }
    static getRelayLabels(component) {
        // TODO:
        //  https://github.com/hashgraph/solo/issues/1823
        //  Add logic for selecting by specific label,
        //  when multiple instances can be deployed at the same time.
        const relayComponent = component;
        const ids = relayComponent.consensusNodeIds;
        // generate label such as relay-node1 or relay-node1-node2
        let label = 'relay';
        for (const id of ids) {
            label += `-${Templates.renderNodeAliasFromNumber(id + 1)}`;
        }
        return [`app.kubernetes.io/instance=${label}`];
    }
    static getHaProxyLabels(component) {
        const nodeAlias = Templates.renderNodeAliasFromNumber(component.metadata.id + 1);
        return [`app=haproxy-${nodeAlias}`, 'solo.hedera.com/type=haproxy'];
    }
    static getMirrorNodeLabels() {
        // TODO:
        //  https://github.com/hashgraph/solo/issues/1823
        //  Add logic for selecting by specific label,
        //  when multiple instances can be deployed at the same time.
        return ['app.kubernetes.io/component=importer', 'app.kubernetes.io/name=importer'];
    }
    static getEnvoyProxyLabels(component) {
        const nodeAlias = Templates.renderNodeAliasFromNumber(component.metadata.id + 1);
        return [`solo.hedera.com/node-name=${nodeAlias}`, 'solo.hedera.com/type=envoy-proxy'];
    }
    static getMirrorNodeExplorerLabels() {
        // TODO:
        //  https://github.com/hashgraph/solo/issues/1823
        //  Add logic for selecting by specific label,
        //  when multiple instances can be deployed at the same time.
        return [constants.SOLO_EXPLORER_LABEL];
    }
    static getConsensusNodeLabels(component) {
        return [`app=network-${Templates.renderNodeAliasFromNumber(component.metadata.id + 1)}`];
    }
    static consensusNodeSkipConditionCallback(nodeComponent) {
        return (nodeComponent.metadata.phase === DeploymentPhase.REQUESTED ||
            nodeComponent.metadata.phase === DeploymentPhase.STOPPED);
    }
    static getBlockNodeLabels() {
        return [`app.kubernetes.io/name=${constants.BLOCK_NODE_RELEASE_NAME}-0`];
    }
    static componentValidationsMapping = {
        relayNodes: {
            displayName: 'Relay Nodes',
            getLabelsCallback: RemoteConfigValidator_1.getRelayLabels,
        },
        haProxies: {
            displayName: 'HaProxy',
            getLabelsCallback: RemoteConfigValidator_1.getHaProxyLabels,
        },
        mirrorNodes: {
            displayName: 'Mirror Node',
            getLabelsCallback: RemoteConfigValidator_1.getMirrorNodeLabels,
        },
        envoyProxies: {
            displayName: 'Envoy Proxy',
            getLabelsCallback: RemoteConfigValidator_1.getEnvoyProxyLabels,
        },
        explorers: {
            displayName: 'Explorer',
            getLabelsCallback: RemoteConfigValidator_1.getMirrorNodeExplorerLabels,
        },
        consensusNodes: {
            displayName: 'Consensus Node',
            getLabelsCallback: RemoteConfigValidator_1.getConsensusNodeLabels,
            skipCondition: RemoteConfigValidator_1.consensusNodeSkipConditionCallback,
        },
        blockNodes: {
            displayName: 'Block Node',
            getLabelsCallback: RemoteConfigValidator_1.getBlockNodeLabels,
        },
    };
    async validateComponents(namespace, skipConsensusNodes, state) {
        const validationPromises = Object.entries(RemoteConfigValidator_1.componentValidationsMapping)
            .filter(([key]) => key !== 'consensusNodes' || !skipConsensusNodes)
            .flatMap(([key, { getLabelsCallback, displayName, skipCondition }]) => this.validateComponentGroup(namespace, state[key], getLabelsCallback, displayName, skipCondition));
        await Promise.all(validationPromises);
    }
    validateComponentGroup(namespace, components, getLabelsCallback, displayName, skipCondition) {
        return components.map(async (component) => {
            if (skipCondition?.(component)) {
                return;
            }
            const context = this.localConfig.configuration.clusterRefs.get(component.metadata.cluster)?.toString();
            let labels = getLabelsCallback(component);
            // special handling of explorer scheme since its label changed
            if (component instanceof ExplorerStateSchema && component.version) {
                const chartVersion = new SemVer(component.version);
                const oldVersion = new SemVer(EXPLORER_OLD_VERSION_BEFORE_LABEL_CHANGE);
                if (chartVersion.compare(oldVersion) <= 0) {
                    labels = [constants.OLD_SOLO_EXPLORER_LABEL];
                }
            }
            try {
                const pods = await this.k8Factory.getK8(context).pods().list(namespace, labels);
                if (pods.length === 0) {
                    throw new Error('Pod not found'); // to return the generic error message
                }
            }
            catch (error) {
                throw RemoteConfigValidator_1.buildValidationError(displayName, component, error);
            }
        });
    }
    /**
     * Generic handler that throws errors.
     *
     * @param displayName - name to display in error message
     * @param component - component which is not found in the cluster
     * @param error - original error for the kube client
     */
    static buildValidationError(displayName, component, error) {
        return new SoloError(RemoteConfigValidator_1.buildValidationErrorMessage(displayName, component), error, component);
    }
    static buildValidationErrorMessage(displayName, component) {
        return (`${displayName} in remote config with id ${component.metadata.id} was not found in ` +
            `namespace: ${component.metadata.namespace}, ` +
            `cluster: ${component.metadata.cluster}`);
    }
};
RemoteConfigValidator = RemoteConfigValidator_1 = __decorate([
    injectable(),
    __param(0, inject(InjectTokens.K8Factory)),
    __param(1, inject(InjectTokens.LocalConfigRuntimeState)),
    __metadata("design:paramtypes", [Object, Function])
], RemoteConfigValidator);
export { RemoteConfigValidator };
//# sourceMappingURL=remote-config-validator.js.map