"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.normalizeSSHKey = normalizeSSHKey;
exports.testSFTPConnection = testSFTPConnection;
exports.uploadSFTP = uploadSFTP;
const actions_core_1 = require("@segment/actions-core");
const path_1 = __importDefault(require("path"));
const ssh2_sftp_client_1 = __importDefault(require("ssh2-sftp-client"));
const constants_1 = require("./constants");
const sftp_wrapper_1 = require("./sftp-wrapper");
var SFTPErrorCode;
(function (SFTPErrorCode) {
    SFTPErrorCode[SFTPErrorCode["NO_SUCH_FILE"] = 2] = "NO_SUCH_FILE";
})(SFTPErrorCode || (SFTPErrorCode = {}));
async function uploadSFTP(settings, sftpFolderPath, filename, fileContent, logger, signal) {
    const sftp = new sftp_wrapper_1.SFTPWrapper('uploadSFTP', logger);
    signal?.throwIfAborted();
    const abortListener = () => {
        sftp.end().catch(() => {
            logger?.warn('Failed to close SFTP connection');
        });
        throw new actions_core_1.RequestTimeoutError();
    };
    signal?.addEventListener('abort', abortListener, { once: true });
    try {
        await sftp.connect(createConnectionConfig(settings));
        const remoteFilePath = path_1.default.posix.join(sftpFolderPath, filename);
        if (settings.uploadStrategy === constants_1.UploadStrategy.CONCURRENT) {
            return await sftp.fastPutFromBuffer(fileContent, remoteFilePath);
        }
        else {
            return await sftp.put(fileContent, remoteFilePath);
        }
    }
    catch (e) {
        formatAndThrowError(e, sftpFolderPath);
    }
    finally {
        await sftp.end();
        signal?.removeEventListener('abort', abortListener);
    }
}
function createConnectionConfig(settings) {
    const { auth_type, sftp_ssh_key, sftp_password } = settings;
    const credentialKey = auth_type === 'ssh_key' ? 'privateKey' : 'password';
    const credentialValue = auth_type === 'ssh_key' ? normalizeSSHKey(sftp_ssh_key) : sftp_password;
    return {
        host: settings.sftp_host,
        port: settings.sftp_port || constants_1.SFTP_DEFAULT_PORT,
        username: settings.sftp_username,
        [credentialKey]: credentialValue
    };
}
function normalizeSSHKey(key = '') {
    if (!key)
        return key;
    const normalizedKey = key.trim().replace(/\r\n/g, '\n').replace(/\r/g, '\n');
    const properFormat = /-----BEGIN [A-Z\s]+PRIVATE KEY-----\n[\s\S]*?\n-----END [A-Z\s]+PRIVATE KEY-----/;
    const hasProperFormat = properFormat.test(normalizedKey);
    if (hasProperFormat)
        return normalizedKey;
    const headerMatch = normalizedKey.match(/(-----BEGIN [A-Z\s]+PRIVATE KEY-----)/);
    const footerMatch = normalizedKey.match(/(-----END [A-Z\s]+PRIVATE KEY-----)/);
    if (headerMatch && footerMatch) {
        const header = headerMatch[1];
        const footer = footerMatch[1];
        const keyContent = normalizedKey.replace(header, '').replace(footer, '').replace(/\s/g, '');
        const formattedContent = keyContent.replace(/.{64}/g, '$&\n').replace(/\n$/, '');
        return `${header}\n${formattedContent}\n${footer}`;
    }
    return normalizedKey;
}
async function testSFTPConnection(settings) {
    const sftp = new ssh2_sftp_client_1.default();
    const timeoutPromise = new Promise((_, reject) => {
        setTimeout(() => {
            reject(new actions_core_1.RequestTimeoutError('SFTP connection timed out'));
        }, actions_core_1.DEFAULT_REQUEST_TIMEOUT);
    });
    return Promise.race([timeoutPromise, connectAndList(sftp, settings)]);
}
async function connectAndList(sftp, settings) {
    let res;
    try {
        await sftp.connect(createConnectionConfig(settings));
        res = await sftp.list('/');
    }
    catch (e) {
        formatAndThrowError(e);
    }
    finally {
        await sftp.end();
    }
    return res;
}
function formatAndThrowError(e, path = '/') {
    const sftpError = e;
    if (sftpError) {
        if (sftpError.code === SFTPErrorCode.NO_SUCH_FILE) {
            throw new actions_core_1.PayloadValidationError(`Could not find path: ${path}`);
        }
    }
    throw new actions_core_1.IntegrationError(`SFTP Error: ${e.message || 'Unknown error'}`, 'SFTP_ERROR', 500);
}
//# sourceMappingURL=client.js.map