"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SFTPWrapper = void 0;
const ssh2_sftp_client_1 = __importDefault(require("ssh2-sftp-client"));
class SFTPWrapper {
    constructor(name, logger) {
        this.sftp = new ssh2_sftp_client_1.default(name);
        this.logger = logger;
    }
    async connect(options) {
        try {
            this.client = await this.sftp.connect(options);
            return this.client;
        }
        catch (error) {
            this.logger?.error('Error connecting to SFTP server:', String(error));
            throw error;
        }
    }
    async put(buffer, remoteFilePath, options = {}) {
        if (!this.client) {
            throw new Error('SFTP Client not connected. Call connect first.');
        }
        try {
            return await this.sftp.put(buffer, remoteFilePath, options);
        }
        catch (error) {
            this.logger?.error('Error uploading file to SFTP server:', String(error));
            throw error;
        }
    }
    async fastPutFromBuffer(input, remoteFilePath, options = {}) {
        if (!this.client) {
            throw new Error('SFTP Client not connected. Call connect first.');
        }
        try {
            return this._fastXferFromBuffer(input, remoteFilePath, options);
        }
        catch (error) {
            this.logger?.error('Error uploading buffer to SFTP server:', String(error));
            throw error;
        }
    }
    async _fastXferFromBuffer(input, remoteFilePath, options) {
        const fsize = input.length;
        return new Promise((resolve, reject) => {
            this.client?.open(remoteFilePath, 'w', (err, handle) => {
                if (err) {
                    return reject(new Error(`Error opening remote file: ${err.message}`));
                }
                const concurrency = options.concurrency || 64;
                const chunkSize = options.chunkSize || 32768;
                const readBuffer = input;
                let position = 0;
                let writeRequests = [];
                const writeChunk = (chunkPos) => {
                    return new Promise((chunkResolve, chunkReject) => {
                        const bytesToWrite = Math.min(chunkSize, fsize - chunkPos);
                        if (bytesToWrite <= 0) {
                            return chunkResolve();
                        }
                        this.client?.write(handle, readBuffer, chunkPos, bytesToWrite, chunkPos, (writeErr) => {
                            if (writeErr) {
                                return chunkReject(new Error(`Error writing to remote file: ${writeErr.message}`));
                            }
                            chunkResolve();
                        });
                    });
                };
                const processWrites = async () => {
                    while (position < fsize) {
                        writeRequests.push(writeChunk(position));
                        position += chunkSize;
                        if (writeRequests.length >= concurrency) {
                            await Promise.all(writeRequests);
                            writeRequests = [];
                        }
                    }
                    await Promise.all(writeRequests);
                };
                processWrites()
                    .then(resolve)
                    .catch(reject)
                    .finally(() => {
                    this.client?.close(handle, (closeErr) => {
                        if (closeErr) {
                            this.logger?.warn('Error closing remote file handle:', String(closeErr.message));
                        }
                    });
                });
            });
        });
    }
    async end() {
        return this.sftp.end();
    }
}
exports.SFTPWrapper = SFTPWrapper;
//# sourceMappingURL=sftp-wrapper.js.map