import os from 'node:os';
import pkg from 'ssh2';
const { utils } = pkg;
import constants from '../constants.js';
export default class BuildHostProvisioner {
    _BUILD_HOST_KEY_BITS = 2048;
    _BUILD_HOST_KEY_CIPHER = 'aes256-cbc';
    _BUILD_HOST_KEY_TYPE = 'rsa';
    cloudClient;
    constructor(cloudClient) {
        this.cloudClient = cloudClient;
    }
    async provision(region) {
        const templateId = await this.getRemoteDockerHostTemplateId(region);
        const { environmentId, sshHost, sshPort } = await this.createEnvironment(templateId);
        const { privateKey, publicKey } = await this.getKeyPair();
        await this.addSshKeyToEnvironment(environmentId, publicKey);
        return { environmentId, privateKey, publicKey, sshHost, sshPort };
    }
    async addSshKeyToEnvironment(cloudBuildHostEnvironmentId, publicKey) {
        const sshPublicKeyBase64 = Buffer.from(publicKey).toString('base64');
        await this.cloudClient.put(`/configurations/${cloudBuildHostEnvironmentId}/user_data`, {
            "contents": JSON.stringify({ "ssh_public_key_base64": sshPublicKeyBase64 })
        });
    }
    async createEnvironment(templateId) {
        const configs = await this.cloudClient.post("/configurations", {
            "name": `Cloud Scripts Build Host - ${os.userInfo().username}`,
            "template_id": templateId,
        });
        const vm = configs.vms[0];
        const networkInterface = vm.interfaces[0];
        let sshService = networkInterface.services?.find((service) => service.internal_port === constants.SSH_PORT);
        if (!sshService) {
            sshService = await this.cloudClient.post(`/configurations/${configs.id}/vms/${vm.id}/interfaces/${networkInterface.id}/services`, { "internal_port": constants.SSH_PORT });
        }
        return {
            environmentId: configs.id,
            sshHost: sshService.external_ip,
            sshPort: sshService.external_port
        };
    }
    async getKeyPair() {
        return new Promise((resolve, reject) => {
            utils.generateKeyPair(this._BUILD_HOST_KEY_TYPE, {
                bits: this._BUILD_HOST_KEY_BITS, cipher: this._BUILD_HOST_KEY_CIPHER
            }, (err, keys) => {
                if (err) {
                    reject(err);
                }
                else {
                    resolve({ privateKey: keys.private, publicKey: keys.public });
                }
            });
        });
    }
    async getRemoteDockerHostTemplateId(region) {
        const templates = await this.cloudClient.get(`/templates?sort=created_at_desc&filter=${constants.CLOUD_TEMPLATE_BUILD_HOST_SEARCH_STRING}`);
        const template = templates?.find((template) => template.region?.toLowerCase() === region?.toLowerCase());
        if (template) {
            return template.id;
        }
        throw new Error(`There was no Build Host template found in region "${region}".`);
    }
}
