// Type definitions imported from DefinitielyTyped for webpack-notifier 1.13
// Project: https://github.com/Turbo87/webpack-notifier#readme
// Definitions by: Benjamin Lim <https://github.com/bumbleblym>
//                 Piotr Błażejewicz <https://github.com/peterblazejewicz>
//                 Alexandre Germain <https://github.com/gerkindev>
//                 Gvozdev Viktor <https://github.com/Gvozd>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 3.9

import { Compiler } from 'webpack';
import nodeNotifier = require('node-notifier');

export = WebpackNotifierPlugin;

declare class WebpackNotifierPlugin {
    constructor(options?: WebpackNotifierPlugin.Options);
    apply(compiler: Compiler): void;
}

declare namespace WebpackNotifierPlugin {
    interface Options {
        alwaysNotify?: boolean;
        contentImage?: {[key in 'success' | 'warning' | 'error']: string} | string;
        excludeWarnings?: boolean;
        onlyOnError?: boolean;
        skipFirstNotification?: boolean;
        title?: string | TitleGetter;
        /**
         * Use emoji in notifications
         */
        emoji?: boolean;
        /**
         * Additional options passed to `node-notifier` on every notification
         *
         * @since v1.17.0
         */
        notifyOptions?: NotifyOptions;
        /**
         * `node-notifier` notifier to use: the name of one of its exported
         * notifier classes ('NotificationCenter', 'WindowsToaster',
         * 'WindowsBalloon', 'Growl', 'NotifySend') or the class itself
         *
         * @since v1.17.0
         */
        notifier?: string | NotifierConstructor;
        /**
         * Options passed to the notifier constructor (see `notifier`)
         *
         * @since v1.17.0
         */
        notifierOptions?: NotifierConstructorOptions;
    }

    type NotificationCenter = typeof nodeNotifier.NotificationCenter;
    type WindowsToaster = typeof nodeNotifier.WindowsToaster;
    type WindowsBalloon = typeof nodeNotifier.WindowsBalloon;
    type NotifySend = typeof nodeNotifier.NotifySend;
    type Growl = typeof nodeNotifier.Growl;

    type NotifyOptionsOf<C extends new (...args: any[]) => any> =
        NonNullable<Parameters<InstanceType<C>['notify']>[0]>;
    type ConstructorOptionsOf<C extends new (...args: any[]) => any> =
        NonNullable<ConstructorParameters<C>[0]>;

    /**
     * Options accepted by the `notify` method of any node-notifier notifier.
     * When no `notifier` is set, all of these are available. The plugin
     * generates `title`, `message`, `contentImage` and `icon` itself, so those
     * are not accepted here.
     */
    type NotifyOptions = DistributiveOmit<
        | NotifyOptionsOf<NotificationCenter>
        | NotifyOptionsOf<WindowsToaster>
        | NotifyOptionsOf<WindowsBalloon>
        | NotifyOptionsOf<NotifySend>
        | NotifyOptionsOf<Growl>,
        PluginGeneratedFields
    >;

    /** notify options generated by the plugin and not accepted in notifyOptions */
    type PluginGeneratedFields = 'title' | 'message' | 'contentImage' | 'icon';

    type DistributiveOmit<T, K extends keyof any> = T extends any ? Omit<T, K> : never;

    /**
     * Options accepted by the constructor of any node-notifier notifier.
     */
    type NotifierConstructorOptions =
        | ConstructorOptionsOf<NotificationCenter>
        | ConstructorOptionsOf<WindowsToaster>
        | ConstructorOptionsOf<WindowsBalloon>
        | ConstructorOptionsOf<NotifySend>
        | ConstructorOptionsOf<Growl>;

    /**
     * A node-notifier notifier class, e.g. `require('node-notifier').WindowsToaster`.
     */
    type NotifierConstructor = new (options?: object) => {
        notify(options: object, callback?: (...args: unknown[]) => void): unknown;
    };

    /** @deprecated use Options */
    type Config = Options;

    type TitleGetter = (data: {msg: string,message: string,status: string}) => string;
}
