import * as tls from 'tls'
import { Stats } from 'fs'
import { EventEmitter } from 'events';

export class FileSystem {

	readonly connection: FtpConnection;
	readonly root: string;
	readonly cwd: string;

    constructor(connection: FtpConnection, {root, cwd}?: {
      root: any;
      cwd: any;
    });

    currentDirectory(): string;

    get(fileName: string): Promise<any>;

    list(path?: string): Promise<any>;

    chdir(path?: string): Promise<string>;

    protected _resolvePath(path?: string): {
      clientPath: string,
      fsPath: string
    };

    write(fileName: string, {append, start}?: {
      append?: boolean;
      start?: any;
    }): any;

    read(fileName: string, {start}?: {
      start?: any;
    }): Promise<any>;

    delete(path: string): Promise<any>;

    mkdir(path: string): Promise<any>;

    rename(from: string, to: string): Promise<any>;

    chmod(path: string, mode: string): Promise<any>;

    getUniqueName(fileName: string): string;
}

export class GeneralError extends Error {
  /**
   * @param message The error message.
   * @param code Default value is `400`.
   */
  constructor(message: string, code?: number);
}

export class SocketError extends Error {
  /**
   * @param message The error message.
   * @param code Default value is `500`.
   */
  constructor(message: string, code?: number);
}

export class FileSystemError extends Error {
  /**
   * @param message The error message.
   * @param code Default value is `400`.
   */
  constructor(message: string, code?: number);
}

export class ConnectorError extends Error {
  /**
   * @param message The error message.
   * @param code Default value is `400`.
   */
  constructor(message: string, code?: number);
}

export class FtpConnection extends EventEmitter {
	server: FtpServer;
	id: string;
	log: any;
	transferType: string;
	encoding: string;
	bufferSize: boolean;
	readonly ip: string;
	restByteCount: number | undefined;
	secure: boolean

	close (code: number, message: number): Promise<any>
	login (username: string, password: string): Promise<any>
	reply (options: number | Object, ...letters: Array<any>): Promise<any>
}

export interface FtpServerOptions {
  url?: string,
  pasv_min?: number,
  pasv_max?: number,
  pasv_hostname?: string,
  greeting?: string | string[],
  tls?: tls.SecureContextOptions | false,
  anonymous?: boolean,
  blacklist?: Array<string>,
  whitelist?: Array<string>,
  list_format?: (stat: Stats) => string | Promise<string> | "ls" | "ep",
	log?: any,
	timeout?: number
}

export class FtpServer extends EventEmitter {
  constructor(options?: FtpServerOptions);

  readonly isTLS: boolean;

  listen(): any;

  emitPromise(action: any, ...data: any[]): Promise<any>;

  // emit is exported from super class

  setupTLS(_tls: boolean): boolean | {
    cert: string;
    key: string;
    ca: string
  };

  setupGreeting(greet: string): string[];

  setupFeaturesMessage(): string;

  disconnectClient(id: string): Promise<any>;

  close(): any;

	on(event: "login", listener: (
		data: {
			connection: FtpConnection,
			username: string,
			password: string
		},
		resolve: (config: {
      fs?: FileSystem,
      root?: string,
      cwd?: string,
      blacklist?: Array<string>,
      whitelist?: Array<string>
    }) => void,
		reject: (err?: Error) => void
  ) => void): this;

	on(event: "disconnect", listener: (
		data: {
      connection: FtpConnection,
      id: string
		}
	) => void): this;

	on(event: "client-error", listener: (
		data: {
			connection: FtpConnection,
			context: string,
			error: Error,
		}
	) => void): this;
}

export {FtpServer as FtpSrv};
export default FtpServer;
