// SPDX-License-Identifier: Apache-2.0
import { AccountId, PrivateKey, PublicKey } from '@hiero-ledger/sdk';
import { GenesisNetworkNodeDataWrapper } from './genesis-network-node-data-wrapper.js';
import * as constants from '../constants.js';
import { GenesisNetworkRosterEntryDataWrapper } from './genesis-network-roster-entry-data-wrapper.js';
import { Templates } from '../templates.js';
import { SoloError } from '../errors/solo-error.js';
import { Flags as flags } from '../../commands/flags.js';
import { PathEx } from '../../business/utils/path-ex.js';
/**
 * Used to construct the nodes data and convert them to JSON
 */
export class GenesisNetworkDataConstructor {
    consensusNodes;
    keyManager;
    accountManager;
    keysDirectory;
    networkNodeServiceMap;
    adminPublicKeyMap;
    domainNamesMapping;
    nodes = {};
    rosters = {};
    initializationPromise;
    constructor(consensusNodes, keyManager, accountManager, keysDirectory, networkNodeServiceMap, adminPublicKeyMap, domainNamesMapping) {
        this.consensusNodes = consensusNodes;
        this.keyManager = keyManager;
        this.accountManager = accountManager;
        this.keysDirectory = keysDirectory;
        this.networkNodeServiceMap = networkNodeServiceMap;
        this.adminPublicKeyMap = adminPublicKeyMap;
        this.domainNamesMapping = domainNamesMapping;
        this.initializationPromise = (async () => {
            for (const consensusNode of consensusNodes) {
                let adminPublicKey;
                const networkNodeService = this.networkNodeServiceMap.get(consensusNode.name);
                const accountId = AccountId.fromString(networkNodeService.accountId);
                const namespace = networkNodeService.namespace;
                if (adminPublicKeyMap.has(consensusNode.name)) {
                    try {
                        if (PublicKey.fromStringED25519(adminPublicKeyMap.get(consensusNode.name))) {
                            adminPublicKey = PublicKey.fromStringED25519(adminPublicKeyMap.get(consensusNode.name));
                        }
                    }
                    catch {
                        // Ignore error
                    }
                }
                try {
                    // not found existing one, generate a new key, and save to k8s secret
                    if (!adminPublicKey) {
                        const newKey = PrivateKey.generateED25519();
                        adminPublicKey = newKey.publicKey;
                        try {
                            await this.accountManager.createOrReplaceAccountKeySecret(newKey, accountId, false, namespace);
                        }
                        catch {
                            throw new SoloError(`failed to create secret for admin key of: ${accountId.toString()}`);
                        }
                    }
                    const nodeDataWrapper = new GenesisNetworkNodeDataWrapper(+networkNodeService.nodeId, adminPublicKey, consensusNode.name);
                    this.nodes[consensusNode.name] = nodeDataWrapper;
                    nodeDataWrapper.accountId = accountId;
                    const rosterDataWrapper = new GenesisNetworkRosterEntryDataWrapper(+networkNodeService.nodeId);
                    this.rosters[consensusNode.name] = rosterDataWrapper;
                    rosterDataWrapper.weight = this.nodes[consensusNode.name].weight = constants.HEDERA_NODE_DEFAULT_STAKE_AMOUNT;
                    const externalPort = +constants.HEDERA_NODE_EXTERNAL_GOSSIP_PORT;
                    // Add gossip endpoints
                    nodeDataWrapper.addGossipEndpoint(networkNodeService.externalAddress, externalPort);
                    rosterDataWrapper.addGossipEndpoint(networkNodeService.externalAddress, externalPort);
                    const domainName = domainNamesMapping?.[consensusNode.name];
                    // Add service endpoints
                    nodeDataWrapper.addServiceEndpoint(domainName ?? networkNodeService.externalAddress, constants.GRPC_PORT);
                }
                catch (error) {
                    throw new SoloError(error.message, error);
                }
            }
        })();
    }
    static async initialize(consensusNodes, keyManager, accountManager, keysDirectory, networkNodeServiceMap, adminPublicKeys, domainNamesMapping) {
        const adminPublicKeyMap = new Map();
        let adminPublicKeyIsDefaultValue = true;
        for (const publicKey of adminPublicKeys) {
            if (publicKey !== flags.adminPublicKeys.definition.defaultValue) {
                adminPublicKeyIsDefaultValue = false;
            }
        }
        // If admin keys are passed and if it is not the default value from flags then validate and build the adminPublicKeyMap
        if (adminPublicKeys.length > 0 && !adminPublicKeyIsDefaultValue) {
            if (adminPublicKeys.length !== consensusNodes.length) {
                throw new SoloError(`Provide a comma separated list of DER encoded ED25519 public keys for each node, adminPublicKeys.length=${adminPublicKeys.length} does not match consensusNodes.length=${consensusNodes.length}`);
            }
            for (const [index, key] of adminPublicKeys.entries()) {
                adminPublicKeyMap.set(consensusNodes[index].name, key);
            }
        }
        const instance = new GenesisNetworkDataConstructor(consensusNodes, keyManager, accountManager, keysDirectory, networkNodeServiceMap, adminPublicKeyMap, domainNamesMapping);
        await instance.load();
        return instance;
    }
    /**
     * Loads the gossipCaCertificate and grpcCertificateHash
     */
    async load() {
        await this.initializationPromise;
        await Promise.all(this.consensusNodes.map(async (consensusNode) => {
            const signingCertFile = Templates.renderGossipPemPublicKeyFile(consensusNode.name);
            const signingCertFullPath = PathEx.joinWithRealPath(this.keysDirectory, signingCertFile);
            const derCertificate = this.keyManager.getDerFromPemCertificate(signingCertFullPath);
            //* Assign the DER formatted certificate
            this.rosters[consensusNode.name].gossipCaCertificate = this.nodes[consensusNode.name].gossipCaCertificate =
                Buffer.from(derCertificate).toString('base64');
            //* Generate the SHA-384 hash
            this.nodes[consensusNode.name].grpcCertificateHash = '';
        }));
    }
    toJSON() {
        const nodeMetadata = [];
        for (const nodeAlias of Object.keys(this.nodes)) {
            nodeMetadata.push({
                node: this.nodes[nodeAlias].toObject(),
                rosterEntry: this.rosters[nodeAlias].toObject(),
            });
        }
        return JSON.stringify({ nodeMetadata: nodeMetadata });
    }
}
//# sourceMappingURL=genesis-network-data-constructor.js.map