// Type definitions for fs-extra 9.0
// Project: https://github.com/jprichardson/node-fs-extra
// Definitions by: Alan Agius <https://github.com/alan-agius4>,
//                 midknight41 <https://github.com/midknight41>,
//                 Brendan Forster <https://github.com/shiftkey>,
//                 Mees van Dijk <https://github.com/mees->,
//                 Justin Rockwood <https://github.com/jrockwood>,
//                 Sang Dang <https://github.com/sangdth>,
//                 Florian Keller <https://github.com/ffflorian>
//                 Piotr Błażejewicz <https://github.com/peterblazejewicz>
//                 Tiger Oakes <https://github.com/NotWoods>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// Minimum TypeScript Version: 3.9

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

import * as fs from 'fs';
import Stats = fs.Stats;
import PathLike = fs.PathLike;

export * from 'fs';

export function copy(src: string, dest: string, options?: CopyOptions): Promise<void>;
export function copy(src: string, dest: string, callback: (err: Error) => void): void;
export function copy(src: string, dest: string, options: CopyOptions, callback: (err: Error) => void): void;
export function copySync(src: string, dest: string, options?: CopyOptionsSync): void;

export function copyFile(src: string, dest: string, flags?: number): Promise<void>;
export function copyFile(src: string, dest: string, callback: (err: Error) => void): void;
export function copyFile(src: string, dest: string, flags: number, callback: (err: Error) => void): void;

export function move(src: string, dest: string, options?: MoveOptions): Promise<void>;
export function move(src: string, dest: string, callback: (err: Error) => void): void;
export function move(src: string, dest: string, options: MoveOptions, callback: (err: Error) => void): void;
export function moveSync(src: string, dest: string, options?: MoveOptions): void;

export function createFile(file: string): Promise<void>;
export function createFile(file: string, callback: (err: Error) => void): void;
export function createFileSync(file: string): void;

export function createSymlink(src: string, dest: string, type: SymlinkType): Promise<void>;
export function createSymlink(src: string, dest: string, type: SymlinkType, callback?: (err: Error) => void): void;
export function createSymlinkSync(src: string, dest: string, type: SymlinkType): void;

export function ensureDir(path: string, options?: EnsureOptions | number): Promise<void>;
export function ensureDir(path: string, callback?: (err: Error) => void): void;
export function ensureDir(path: string, options?: EnsureOptions | number, callback?: (err: Error) => void): void;
export function ensureDirSync(path: string, options?: EnsureOptions | number): void;

export function mkdirs(dir: string): Promise<void>;
export function mkdirs(dir: string, callback: (err: Error) => void): void;
export function mkdirp(dir: string): Promise<void>;
export function mkdirp(dir: string, callback: (err: Error) => void): void;
export function mkdirsSync(dir: string): void;
export function mkdirpSync(dir: string): void;

export function outputFile(
    file: string,
    data: any,
    options?: WriteFileOptions | BufferEncoding | string,
): Promise<void>;
export function outputFile(file: string, data: any, callback: (err: Error) => void): void;
export function outputFile(
    file: string,
    data: any,
    options: WriteFileOptions | string,
    callback: (err: Error) => void,
): void;
export function outputFileSync(file: string, data: any, options?: WriteFileOptions | BufferEncoding | string): void;

export function readJson(file: string, options?: ReadOptions | BufferEncoding | string): Promise<any>;
export function readJson(file: string, callback: (err: Error, jsonObject: any) => void): void;
export function readJson(
    file: string,
    options: ReadOptions | BufferEncoding | string,
    callback: (err: Error, jsonObject: any) => void,
): void;
export function readJSON(file: string, options?: ReadOptions | BufferEncoding | string): Promise<any>;
export function readJSON(file: string, callback: (err: Error, jsonObject: any) => void): void;
export function readJSON(
    file: string,
    options: ReadOptions | BufferEncoding | string,
    callback: (err: Error, jsonObject: any) => void,
): void;

export function readJsonSync(file: string, options?: ReadOptions | BufferEncoding | string): any;
export function readJSONSync(file: string, options?: ReadOptions | BufferEncoding | string): any;

export function remove(dir: string, callback: (err: Error) => void): void;
export function remove(dir: string, callback?: (err: Error) => void): Promise<void>;
export function removeSync(dir: string): void;

export function outputJSON(file: string, data: any, options?: WriteOptions | BufferEncoding | string): Promise<void>;
export function outputJSON(
    file: string,
    data: any,
    options: WriteOptions | BufferEncoding | string,
    callback: (err: Error) => void,
): void;
export function outputJSON(file: string, data: any, callback: (err: Error) => void): void;
export function outputJson(file: string, data: any, options?: WriteOptions | BufferEncoding | string): Promise<void>;
export function outputJson(
    file: string,
    data: any,
    options: WriteOptions | BufferEncoding | string,
    callback: (err: Error) => void,
): void;
export function outputJson(file: string, data: any, callback: (err: Error) => void): void;
export function outputJsonSync(file: string, data: any, options?: WriteOptions | BufferEncoding | string): void;
export function outputJSONSync(file: string, data: any, options?: WriteOptions | BufferEncoding | string): void;

export function writeJSON(file: string, object: any, options?: WriteOptions | BufferEncoding | string): Promise<void>;
export function writeJSON(file: string, object: any, callback: (err: Error) => void): void;
export function writeJSON(
    file: string,
    object: any,
    options: WriteOptions | BufferEncoding | string,
    callback: (err: Error) => void,
): void;
export function writeJson(file: string, object: any, options?: WriteOptions | BufferEncoding | string): Promise<void>;
export function writeJson(file: string, object: any, callback: (err: Error) => void): void;
export function writeJson(
    file: string,
    object: any,
    options: WriteOptions | BufferEncoding | string,
    callback: (err: Error) => void,
): void;

export function writeJsonSync(file: string, object: any, options?: WriteOptions | BufferEncoding | string): void;
export function writeJSONSync(file: string, object: any, options?: WriteOptions | BufferEncoding | string): void;

export function ensureFile(path: string): Promise<void>;
export function ensureFile(path: string, callback: (err: Error) => void): void;
export function ensureFileSync(path: string): void;

export function ensureLink(src: string, dest: string): Promise<void>;
export function ensureLink(src: string, dest: string, callback: (err: Error) => void): void;
// alias for ensureLink
export const createLink: typeof ensureLink;
export function ensureLinkSync(src: string, dest: string): void;
// aliased as
export const createLinkSync: typeof ensureLinkSync;

export function ensureSymlink(src: string, dest: string, type?: SymlinkType): Promise<void>;
export function ensureSymlink(src: string, dest: string, type: SymlinkType, callback: (err: Error) => void): void;
export function ensureSymlink(src: string, dest: string, callback: (err: Error) => void): void;
export function ensureSymlinkSync(src: string, dest: string, type?: SymlinkType): void;

export function emptyDir(path: string): Promise<void>;
export function emptyDir(path: string, callback: (err: Error) => void): void;
export const emptydir: typeof emptyDir;

export function emptyDirSync(path: string): void;
export const emptydirSync: typeof emptyDirSync;

export function pathExists(path: string): Promise<boolean>;
export function pathExists(path: string, callback: (err: Error, exists: boolean) => void): void;
export function pathExistsSync(path: string): boolean;

// fs async methods
// copied from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/node/v6/index.d.ts

export function access(path: PathLike, callback: (err: NodeJS.ErrnoException) => void): void;
export function access(path: PathLike, mode: number, callback: (err: NodeJS.ErrnoException) => void): void;
export function access(path: PathLike, mode?: number): Promise<void>;

export function appendFile(
    file: PathLike | number,
    data: any,
    options: {
        encoding?: BufferEncoding | string | undefined;
        mode?: number | string | undefined;
        flag?: string | undefined;
    },
    callback: (err: NodeJS.ErrnoException) => void,
): void;
export function appendFile(file: PathLike | number, data: any, callback: (err: NodeJS.ErrnoException) => void): void;
export function appendFile(
    file: PathLike | number,
    data: any,
    options?:
        | {
              encoding?: BufferEncoding | string | undefined;
              mode?: number | string | undefined;
              flag?: string | undefined;
          }
        | BufferEncoding
        | string,
): Promise<void>;

export function chmod(path: PathLike, mode: Mode, callback: (err: NodeJS.ErrnoException) => void): void;
export function chmod(path: PathLike, mode: Mode): Promise<void>;

export function chown(path: PathLike, uid: number, gid: number): Promise<void>;
export function chown(path: PathLike, uid: number, gid: number, callback: (err: NodeJS.ErrnoException) => void): void;

export function close(fd: number, callback: (err: NodeJS.ErrnoException) => void): void;
export function close(fd: number): Promise<void>;

export function fchmod(fd: number, mode: Mode, callback: (err: NodeJS.ErrnoException) => void): void;
export function fchmod(fd: number, mode: Mode): Promise<void>;

export function fchown(fd: number, uid: number, gid: number, callback: (err: NodeJS.ErrnoException) => void): void;
export function fchown(fd: number, uid: number, gid: number): Promise<void>;

export function fdatasync(fd: number, callback: () => void): void;
export function fdatasync(fd: number): Promise<void>;

export function fstat(fd: number, callback: (err: NodeJS.ErrnoException, stats: Stats) => any): void;
export function fstat(fd: number): Promise<Stats>;

export function fsync(fd: number, callback: (err: NodeJS.ErrnoException) => void): void;
export function fsync(fd: number): Promise<void>;

export function ftruncate(fd: number, callback: (err: NodeJS.ErrnoException) => void): void;
export function ftruncate(fd: number, len: number, callback: (err: NodeJS.ErrnoException) => void): void;
export function ftruncate(fd: number, len?: number): Promise<void>;

export function futimes(fd: number, atime: number, mtime: number, callback: (err: NodeJS.ErrnoException) => void): void;
export function futimes(fd: number, atime: Date, mtime: Date, callback: (err: NodeJS.ErrnoException) => void): void;
export function futimes(fd: number, atime: number, mtime: number): Promise<void>;
export function futimes(fd: number, atime: Date, mtime: Date): Promise<void>;

export function lchown(path: PathLike, uid: number, gid: number, callback: (err: NodeJS.ErrnoException) => void): void;
export function lchown(path: PathLike, uid: number, gid: number): Promise<void>;

export function link(existingPath: PathLike, newPath: PathLike, callback: (err: NodeJS.ErrnoException) => void): void;
export function link(existingPath: PathLike, newPath: PathLike): Promise<void>;

export function lstat(path: PathLike, callback: (err: NodeJS.ErrnoException, stats: Stats) => any): void;
export function lstat(path: PathLike): Promise<Stats>;

/**
 * Asynchronous mkdir - creates the directory specified in {path}.  Parameter {mode} defaults to 0777.
 *
 * @param callback No arguments other than a possible exception are given to the completion callback.
 */
export function mkdir(path: PathLike, callback: (err: NodeJS.ErrnoException) => void): void;
/**
 * Asynchronous mkdir - creates the directory specified in {path}.  Parameter {mode} defaults to 0777.
 *
 * @param callback No arguments other than a possible exception are given to the completion callback.