import { StorageEngine } from 'multer';
import { Request } from 'express';
import { Client } from 'minio';
import { Transform, TransformCallback } from 'stream';

/**
 * A transform function that returns a Transform stream (e.g. Sharp).
 */
type FileTransform = (req: Request, file: Express.Multer.File) => NodeJS.ReadWriteStream;
type Dimension = {
    width: number;
    height: number;
};
type ImageMeta = {
    mimetype: string;
    size: number;
    dimension: Dimension;
    key: string;
};
/**
 * An array of transform functions to be applied in sequence.
 */
type MultipleTransforms = Array<FileTransform>;
/**
 * File filter function signature for deciding if a file should be accepted or rejected.
 * Return `true` to accept, or `false` to reject.
 */
type FileFilter = (req: Request, file: Express.Multer.File) => boolean;
/**
 * Function called before upload (e.g., to run validation or logging).
 * You can return a promise or call `await`.
 */
type OnBeforeUpload = (req: Request, file: Express.Multer.File) => Promise<void> | void;
/**
 * A function to compute the object name (filename) to store in MinIO.
 */
type GetObjectName = (req: Request, file: Express.Multer.File, bucket: string) => string;
/**
 * Returns a metadata object for the file, which MinIO stores as object metadata.
 */
type GetMetadata = (req: Request, file: Express.Multer.File) => Record<string, string>;
/**
 * Configuration options for our MinioStorageEngine.
 */
interface MinioStorageOptions {
    client: Client;
    bucket: string;
    prefix?: string;
    getObjectName?: GetObjectName;
    fileFilter?: FileFilter;
    onBeforeUpload?: OnBeforeUpload;
    transforms?: MultipleTransforms;
    transform?: FileTransform;
    metadata?: GetMetadata;
    autoCreateBucket?: boolean;
    trustHeaderSize?: boolean;
    region?: string;
    contentTypeMap?: Record<string, string>;
}

interface CustomStorageEngine extends StorageEngine {
    _handleFile: (req: Request, file: Express.Multer.File, callback: (error?: Error | null, info?: Partial<Express.Multer.File & ImageMeta>) => void) => Promise<void>;
    _removeFile: (req: Request, file: Express.Multer.File, callback: (error: Error | null) => void) => Promise<void>;
}
/**
 * A streaming storage engine for [minio](https://min.io) via [multer](https://www.npmjs.com/package/multer)
 * with added support for image transformations, filters, before-upload hook and metadata.
 */
declare class MinioStreamingStorage implements CustomStorageEngine {
    private readonly client;
    private readonly bucket;
    private readonly prefix?;
    private readonly getObjectName?;
    private readonly fileFilter?;
    private readonly onBeforeUpload?;
    private readonly transforms?;
    private readonly metadata?;
    private readonly autoCreateBucket;
    private readonly trustHeaderSize;
    private readonly region?;
    private readonly contentTypeMap;
    /** Internal Meta from stream */
    private readonly _imageMeta;
    constructor(options: MinioStorageOptions);
    private __ensureBucketExists;
    private _init;
    private _getFutureContentType;
    private _getFutureMeta;
    private _generateObjectName;
    private _generateFullPath;
    private _generatePath;
    private _getMetaFromMap;
    private _getContentSizeFromRequestHeaders;
    _handleFile(req: Request, file: Express.Multer.File, callback: (error?: Error | null, info?: Partial<Express.Multer.File & ImageMeta>) => void): Promise<void>;
    _removeFile(_req: Request, file: Express.Multer.File, callback: (error: Error | null) => void): Promise<void>;
}

/**
 * TODO: WIP
 * A pass-through Transform that counts the total number of bytes.
 * Once the stream finishes, this.bytesRead will be the final size.
 */
declare class CountingStream extends Transform {
    bytesRead: number;
    _transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback): void;
    getBytesRead(): Promise<number>;
}

export { CountingStream, type FileFilter, type FileTransform, type GetMetadata, type GetObjectName, type ImageMeta, type MinioStorageOptions, type MultipleTransforms, type OnBeforeUpload, MinioStreamingStorage as default };
