/// <reference types="node" />

import { ClientRequest, RequestOptions } from "http";
import { Duplex, PassThrough, Readable, Stream, Transform } from "stream";

export interface PullStream extends Duplex {
    stream(eof: number | string, includeEof: boolean): PassThrough;
    pull(eof: number | string, includeEof: boolean): Promise<Buffer>;
}

export interface Entry extends PassThrough {
    autodrain(): Transform & {
        promise(): Promise<void>;
    };
    buffer(): Promise<Buffer>;
    path: string;

    props: {
        path: string;
    };

    type: string;
    vars: {
        signature?: number | undefined;
        versionsNeededToExtract: number;
        flags: number;
        compressionMethod: number;
        lastModifiedTime: number;
        crc32: number;
        compressedSize: number;
        fileNameLength: number;
        extraFieldLength: number;
    };

    extra: {
        signature: number;
        partsize: number;
        uncompressedSize: number;
        compressedSize: number;
        offset: number;
        disknum: number;
    };
}

export function unzip(
    source: {
        stream: Readable;
        size: () => Promise<number>;
    },
    offset: number,
    _password: string,
): Entry;

export namespace Open {
    function buffer(data: Buffer): Promise<CentralDirectory>;
    function file(filename: string): Promise<CentralDirectory>;
    function url(
        request: ClientRequest,
        opt: string | RequestOptions,
    ): Promise<CentralDirectory>;
    function s3(client: any, params: any): Promise<CentralDirectory>;
    function s3_v3(client: any, params: any): Promise<CentralDirectory>;
    function custom(
        source: {
            size: () => Promise<number>;
            stream: (offset: number, length: number) => Readable;
        },
    ): Promise<CentralDirectory>;
}

export function BufferStream(entry: Entry): Promise<Buffer>;

export interface CentralDirectory {
    signature: number;
    diskNumber: number;
    diskStart: number;
    numberOfRecordsOnDisk: number;
    numberOfRecords: number;
    sizeOfCentralDirectory: number;
    offsetToStartOfCentralDirectory: number;
    commentLength: number;
    files: File[];
    extract: (opts: ParseOptions) => Promise<void>;
}

export interface File {
    signature: number;
    versionMadeBy: number;
    versionsNeededToExtract: number;
    flags: number;
    compressionMethod: number;
    lastModifiedTime: number;
    lastModifiedDate: number;
    lastModifiedDateTime: Date;
    crc32: number;
    compressedSize: number;
    uncompressedSize: number;
    fileNameLength: number;
    extraFieldLength: number;
    fileCommentLength: number;
    diskNumber: number;
    internalFileAttributes: number;
    externalFileAttributes: number;
    offsetToLocalFileHeader: number;
    pathBuffer: Buffer;
    path: string;
    isUnicode: number;
    extra: any;
    type: "Directory" | "File";
    comment: string;
    stream: (password?: string) => Entry;
    buffer: (password?: string) => Promise<Buffer>;
}

export interface ParseOptions {
    verbose?: boolean | undefined;
    path?: string | undefined;
    concurrency?: number | undefined;
    forceStream?: boolean | undefined;
}

export type ParseStream = PullStream & {
    promise(): Promise<void>;
};

export function Parse(opts?: ParseOptions): ParseStream;
export function ParseOne(match?: RegExp, opts?: ParseOptions): Duplex;
export function Extract(opts?: ParseOptions): ParseStream;
