// SPDX-License-Identifier: Apache-2.0
import * as x509 from '@peculiar/x509';
import os from 'node:os';
import { DataValidationError } from './errors/data-validation-error.js';
import { IllegalArgumentError } from './errors/illegal-argument-error.js';
import { MissingArgumentError } from './errors/missing-argument-error.js';
import { SoloError } from './errors/solo-error.js';
import * as constants from './constants.js';
import { PodName } from '../integration/kube/resources/pod/pod-name.js';
import { GrpcProxyTlsEnums } from './enumerations.js';
import { HEDERA_PLATFORM_VERSION } from '../../version.js';
import { PathEx } from '../business/utils/path-ex.js';
export class Templates {
    static renderNetworkPodName(nodeAlias) {
        return PodName.of(`network-${nodeAlias}-0`);
    }
    static renderNetworkSvcName(nodeAlias) {
        return `network-${nodeAlias}-svc`;
    }
    static renderNetworkHeadlessSvcName(nodeAlias) {
        return `network-${nodeAlias}`;
    }
    static renderNodeAliasFromNumber(number_) {
        return `node${number_}`;
    }
    static renderNodeAliasesFromCount(count, existingNodesCount) {
        const nodeAliases = [];
        let nodeNumber = existingNodesCount + 1;
        for (let index = 0; index < count; index++) {
            nodeAliases.push(Templates.renderNodeAliasFromNumber(nodeNumber));
            nodeNumber++;
        }
        return nodeAliases;
    }
    static renderGossipPemPrivateKeyFile(nodeAlias) {
        return `${constants.SIGNING_KEY_PREFIX}-private-${nodeAlias}.pem`;
    }
    static renderGossipPemPublicKeyFile(nodeAlias) {
        return `${constants.SIGNING_KEY_PREFIX}-public-${nodeAlias}.pem`;
    }
    static renderTLSPemPrivateKeyFile(nodeAlias) {
        return `hedera-${nodeAlias}.key`;
    }
    static renderTLSPemPublicKeyFile(nodeAlias) {
        return `hedera-${nodeAlias}.crt`;
    }
    static renderNodeAdminKeyName(nodeAlias) {
        return `${nodeAlias}-admin`;
    }
    static renderNodeFriendlyName(prefix, nodeAlias, suffix = '') {
        const parts = [prefix, nodeAlias];
        if (suffix) {
            parts.push(suffix);
        }
        return parts.join('-');
    }
    static extractNodeAliasFromPodName(podName) {
        const parts = podName.name.split('-');
        if (parts.length !== 3) {
            throw new DataValidationError(`pod name is malformed : ${podName.name}`, 3, parts.length);
        }
        return parts[1].trim();
    }
    static prepareReleasePrefix(tag) {
        if (!tag) {
            throw new MissingArgumentError('tag cannot be empty');
        }
        const parsed = tag.split('.');
        if (parsed.length < 3) {
            throw new Error(`tag (${tag}) must include major, minor and patch fields (e.g. v0.40.4)`);
        }
        return `${parsed[0]}.${parsed[1]}`;
    }
    /**
     * renders the name to be used to store the new account key as a Kubernetes secret
     * @param accountId
     * @returns the name of the Kubernetes secret to store the account key
     */
    static renderAccountKeySecretName(accountId) {
        return `account-key-${accountId.toString()}`;
    }
    /**
     * renders the label selector to be used to fetch the new account key from the Kubernetes secret
     * @param accountId
     * @returns the label selector of the Kubernetes secret to retrieve the account key   */
    static renderAccountKeySecretLabelSelector(accountId) {
        return `solo.hedera.com/account-id=${accountId.toString()}`;
    }
    /**
     * renders the label object to be used to store the new account key in the Kubernetes secret
     * @param accountId
     * @returns the label object to be used to store the new account key in the Kubernetes secret
     */
    static renderAccountKeySecretLabelObject(accountId) {
        return {
            'solo.hedera.com/account-id': accountId.toString(),
        };
    }
    static renderDistinguishedName(nodeAlias, state = 'TX', locality = 'Richardson', org = 'Hedera', orgUnit = 'Hedera', country = 'US') {
        return new x509.Name(`CN=${nodeAlias},ST=${state},L=${locality},O=${org},OU=${orgUnit},C=${country}`);
    }
    static renderStagingDir(cacheDirectory, releaseTagOverride) {
        let releaseTag = releaseTagOverride;
        if (!cacheDirectory) {
            throw new IllegalArgumentError('cacheDirectory cannot be empty');
        }
        if (!releaseTag) {
            releaseTag = HEDERA_PLATFORM_VERSION;
        }
        const releasePrefix = this.prepareReleasePrefix(releaseTag);
        if (!releasePrefix) {
            throw new IllegalArgumentError('releasePrefix cannot be empty');
        }
        return PathEx.resolve(PathEx.join(cacheDirectory, releasePrefix, 'staging', releaseTag));
    }
    static installationPath(dep, osPlatform = os.platform(), installationDirectory = PathEx.join(constants.SOLO_HOME_DIR, 'bin')) {
        switch (dep) {
            case constants.HELM:
            case constants.KIND:
            case constants.KUBECTL: {
                if (osPlatform === constants.OS_WINDOWS) {
                    return PathEx.join(installationDirectory, `${dep}.exe`);
                }
                return PathEx.join(installationDirectory, dep);
            }
            default: {
                throw new SoloError(`unknown dep: ${dep}`);
            }
        }
    }
    static renderFullyQualifiedNetworkPodName(namespace, nodeAlias) {
        return `${Templates.renderNetworkPodName(nodeAlias)}.${Templates.renderNetworkHeadlessSvcName(nodeAlias)}.${namespace.name}.svc.cluster.local`;
    }
    static renderFullyQualifiedNetworkSvcName(namespace, nodeAlias) {
        return `${Templates.renderNetworkSvcName(nodeAlias)}.${namespace.name}.svc.cluster.local`;
    }
    static nodeIdFromNodeAlias(nodeAlias) {
        for (let index = nodeAlias.length - 1; index > 0; index--) {
            if (Number.isNaN(Number.parseInt(nodeAlias[index]))) {
                return Number.parseInt(nodeAlias.substring(index + 1, nodeAlias.length)) - 1;
            }
        }
        throw new SoloError(`Can't get node id from node ${nodeAlias}`);
    }
    static renderGossipKeySecretName(nodeAlias) {
        return `network-${nodeAlias}-keys-secrets`;
    }
    static renderGossipKeySecretLabelObject(nodeAlias) {
        return { 'solo.hedera.com/node-name': nodeAlias };
    }
    /**
     * Creates the secret name based on the node alias type
     *
     * @param nodeAlias - node alias
     * @param type - whether is for gRPC or gRPC Web ( Haproxy or Envoy )
     *
     * @returns the appropriate secret name
     */
    static renderGrpcTlsCertificatesSecretName(nodeAlias, type) {
        switch (type) {
            //? HAProxy Proxy
            case GrpcProxyTlsEnums.GRPC: {
                return `haproxy-proxy-secret-${nodeAlias}`;
            }
            //? Envoy Proxy
            case GrpcProxyTlsEnums.GRPC_WEB: {
                return `envoy-proxy-secret-${nodeAlias}`;
            }
        }
    }
    /**
     * Creates the secret labels based on the node alias type
     *
     * @param nodeAlias - node alias
     * @param type - whether is for gRPC or gRPC Web ( Haproxy or Envoy )
     *
     * @returns the appropriate secret labels
     */
    static renderGrpcTlsCertificatesSecretLabelObject(nodeAlias, type) {
        switch (type) {
            //? HAProxy Proxy
            case GrpcProxyTlsEnums.GRPC: {
                return { 'haproxy-proxy-secret': nodeAlias };
            }
            //? Envoy Proxy
            case GrpcProxyTlsEnums.GRPC_WEB: {
                return { 'envoy-proxy-secret': nodeAlias };
            }
        }
    }
    static parseNodeAliasToIpMapping(unparsed) {
        const mapping = {};
        for (const data of unparsed.split(',')) {
            const [nodeAlias, ip] = data.split('=');
            mapping[nodeAlias] = ip;
        }
        return mapping;
    }
    static parseNodeAliasToDomainNameMapping(unparsed) {
        const mapping = {};
        for (const data of unparsed.split(',')) {
            const [nodeAlias, domainName] = data.split('=');
            if (!nodeAlias || typeof nodeAlias !== 'string') {
                throw new SoloError(`Can't parse node alias: ${data}`);
            }
            if (!domainName || typeof domainName !== 'string') {
                throw new SoloError(`Can't parse domain name: ${data}`);
            }
            mapping[nodeAlias] = domainName;
        }
        return mapping;
    }
    /**
     * Renders the fully qualified domain name for a consensus node. We support the following variables for templating
     * in the dnsConsensusNodePattern: {nodeAlias}, {nodeId}, {namespace}, {cluster}
     *
     * The end result will be `${dnsConsensusNodePattern}.${dnsBaseDomain}`.
     * For example, if the dnsConsensusNodePattern is `network-{nodeAlias}-svc.{namespace}.svc` and the dnsBaseDomain is `cluster.local`,
     * the fully qualified domain name will be `network-{nodeAlias}-svc.{namespace}.svc.cluster.local`.
     * @param nodeAlias - the alias of the consensus node
     * @param nodeId - the id of the consensus node
     * @param namespace - the namespace of the consensus node
     * @param cluster - the cluster of the consensus node
     * @param dnsBaseDomain - the base domain of the cluster
     * @param dnsConsensusNodePattern - the pattern to use for the consensus node
     */
    static renderConsensusNodeFullyQualifiedDomainName(nodeAlias, nodeId, namespace, cluster, dnsBaseDomain, dnsConsensusNodePattern) {
        const searchReplace = {
            '{nodeAlias}': nodeAlias,
            '{nodeId}': nodeId.toString(),
            '{namespace}': namespace,
            '{cluster}': cluster,
        };
        for (const [search, replace] of Object.entries(searchReplace)) {
            dnsConsensusNodePattern = dnsConsensusNodePattern.replace(search, replace);
        }
        return `${dnsConsensusNodePattern}.${dnsBaseDomain}`;
    }
    /**
     * @param serviceName - name of the service
     * @param namespace - the pattern to use for the consensus node
     * @param dnsBaseDomain - the base domain of the cluster
     */
    static renderSvcFullyQualifiedDomainName(serviceName, namespace, dnsBaseDomain) {
        return `${serviceName}.${namespace}.svc.${dnsBaseDomain}`;
    }
}
//# sourceMappingURL=templates.js.map