"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.S3StorageFactory = void 0;
const Minio = __importStar(require("minio"));
const url = require('url');
class S3StorageFactory {
    constructor() {
        this.canHandleFileStream = false;
        this.isS3 = true;
    }
    async createFile(name, size, data, contentType, pn, options) {
        const bucket = options?.adapters?.s3Storage?.bucket;
        await this.createBucket(bucket, options);
        this.validateFilename(name);
        return this.saveFile(name, data, bucket, options);
    }
    async deleteFile(filename, options) {
        const bucket = options?.adapters?.s3Storage?.bucket;
        await this.createBucket(bucket, options);
        return this.s3.removeObject(bucket, filename);
    }
    async fileInfo(name, options) {
        const bucket = options?.adapters?.s3Storage?.bucket;
        await this.createBucket(bucket, options);
        const stats = await this.s3.statObject(bucket, name);
        return { size: stats.size, name: name };
    }
    async getFileLocation(filename, configAdapter) {
        return '/storage/' + configAdapter.applicationId + '/file/' + encodeURIComponent(filename);
    }
    validateFilename(filename) {
        const regx = /[^a-zA-Z0-9]/;
        return filename.replace(new RegExp(regx), '');
    }
    handleFileStream(name, req, res, contentType, options) {
        return this.signedUrl(name, options);
    }
    async signedUrl(filename, options) {
        const bucket = options?.adapters?.s3Storage?.bucket;
        await this.createBucket(bucket, options);
        return this.s3.presignedGetObject(bucket, filename, 2 * 60 * 60);
    }
    async listFiles(query = {
        prefix: '',
        after: undefined,
        size: 20
    }, options) {
        const bucket = options?.adapters?.s3Storage?.bucket;
        await this.createBucket(bucket, options);
        const listStream = this.s3.listObjectsV2(bucket, query.prefix, true, query.after);
        const files = [];
        return new Promise((resolve, _) => {
            try {
                listStream.on('data', item => {
                    if (files.length < query.size) {
                        files.push(item);
                    }
                    else {
                        listStream.destroy();
                        listStream.emit('end');
                        return;
                    }
                });
                listStream.on('end', () => {
                    resolve(files);
                });
            }
            catch (_) {
                resolve(files);
            }
        }).then((files) => {
            return files.sort((a, b) => {
                if (a.lastModified.toString() > b.lastModified.toString()) {
                    return 1;
                }
                else if (a.lastModified.toString() < b.lastModified.toString()) {
                    return -1;
                }
                else {
                    return 0;
                }
            });
        });
    }
    async init(options) {
        const endPoint = options.adapters.s3Storage.endPoint;
        const accessKey = options.adapters.s3Storage.accessKey;
        const secretKey = options.adapters.s3Storage.secretKey;
        const bucket = options.adapters.s3Storage.bucket;
        const ep = new url.URL(endPoint);
        const { useSSL = ep.protocol === 'https:' } = options.adapters.s3Storage;
        const { port = ep.port ? +ep.port : (useSSL ? 443 : 80) } = options.adapters.s3Storage;
        const region = S3StorageFactory.getRegion(endPoint, options.adapters.s3Storage.region).trim();
        Object.assign(this, { endPoint, region: `${region}` });
        Object.assign(this, {
            bucket: typeof bucket === 'function'
                ? bucket : () => {
                return `${bucket}`;
            }
        });
        this.s3 = new Minio.Client({
            region,
            endPoint: ep.hostname, accessKey, secretKey, useSSL, port
        });
    }
    async getFileData(id, asStream, options) {
        const bucket = options?.adapters?.s3Storage?.bucket;
        await this.createBucket(bucket, options);
        return this.s3.getObject(bucket, id);
    }
    getFileBuffer(file, options) {
        return this.getFileData(file, true, options);
    }
    getFileStream(id, options) {
        return this.getFileData(id, true, options);
    }
    async saveFile(filename, data, bucket, options) {
        await this.createBucket(bucket, options);
        const v = await this.s3.putObject(bucket, filename, data);
        return { id: filename, name: filename };
    }
    static getRegion(endpoint, region = null) {
        if (region) {
            return region;
        }
        else if (endpoint.includes('amazonaws.')) {
            return endpoint
                .replace('https://', '')
                .replace('http://', '')
                .trim().split('.')[2];
        }
        else {
            return endpoint
                .replace('https://', '')
                .replace('http://', '')
                .trim().split('.')[0];
        }
    }
    async createBucket(bucket, options) {
        const endpoint = options.adapters.s3Storage.endPoint;
        const region = options.adapters.s3Storage.region;
        const bucketExist = await this.s3.bucketExists(bucket);
        if (bucketExist === true) {
        }
        else {
            await this.s3.makeBucket(bucket, S3StorageFactory.getRegion(endpoint, region).trim());
        }
    }
}
exports.S3StorageFactory = S3StorageFactory;
