import React from 'react';

interface CloseButtonProps {
    closeToast: CloseToastFunc;
    type: TypeOptions;
    ariaLabel?: string;
    theme: Theme;
}

/**
 * Used when providing custom icon
 */
interface IconProps {
    theme: Theme;
    type: TypeOptions;
    isLoading?: boolean;
}

type TypeOptions = 'info' | 'success' | 'warning' | 'error' | 'default';
type Theme = 'light' | 'dark' | 'colored' | (string & {});
type ToastPosition = 'top-right' | 'top-center' | 'top-left' | 'bottom-right' | 'bottom-center' | 'bottom-left';
type CloseToastFunc = ((reason?: boolean | string) => void) & ((e: React.MouseEvent) => void);
interface ToastContentProps<Data = unknown> {
    closeToast: CloseToastFunc;
    toastProps: ToastProps;
    isPaused: boolean;
    data: Data;
}
type ToastContent<T = unknown> = React.ReactNode | ((props: ToastContentProps<T>) => React.ReactNode);
type ToastIcon = false | ((props: IconProps) => React.ReactNode) | React.ReactElement<IconProps>;
type Id = number | string;
type ToastTransition = React.FC<ToastTransitionProps> | React.ComponentClass<ToastTransitionProps>;
/**
 * ClassName for the elements - can take a function to build a classname or a raw string that is cx'ed to defaults
 */
type ToastClassName = ((context?: {
    type?: TypeOptions;
    defaultClassName?: string;
    position?: ToastPosition;
    rtl?: boolean;
}) => string) | string;
type DraggableDirection = 'x' | 'y';
interface CommonOptions {
    /**
     * Pause the timer when the mouse hover the toast.
     * `Default: true`
     */
    pauseOnHover?: boolean;
    /**
     * Pause the toast when the window loses focus.
     * `Default: true`
     */
    pauseOnFocusLoss?: boolean;
    /**
     * Remove the toast when clicked.
     * `Default: false`
     */
    closeOnClick?: boolean;
    /**
     * Set the delay in ms to close the toast automatically.
     * Use `false` to prevent the toast from closing.
     * `Default: 5000`
     */
    autoClose?: number | false;
    /**
     * Set the default position to use.
     * `One of: 'top-right', 'top-center', 'top-left', 'bottom-right', 'bottom-center', 'bottom-left'`
     * `Default: 'top-right'`
     */
    position?: ToastPosition;
    /**
     * Pass a custom close button.
     * To remove the close button pass `false`
     */
    closeButton?: boolean | ((props: CloseButtonProps) => React.ReactNode) | React.ReactElement<CloseButtonProps>;
    /**
     * An optional css class to set for the progress bar.
     */
    progressClassName?: ToastClassName;
    /**
     * Hide or show the progress bar.
     * `Default: false`
     */
    hideProgressBar?: boolean;
    /**
     * Pass a custom transition see https://fkhadra.github.io/react-toastify/custom-animation/
     */
    transition?: ToastTransition;
    /**
     * Allow toast to be draggable
     * `Default: 'touch'`
     */
    draggable?: boolean | 'mouse' | 'touch';
    /**
     * The percentage of the toast's width it takes for a drag to dismiss a toast
     * `Default: 80`
     */
    draggablePercent?: number;
    /**
     * Specify in which direction should you swipe to dismiss the toast
     * `Default: "x"`
     */
    draggableDirection?: DraggableDirection;
    /**
     * Define the ARIA role for the toast
     * `Default: alert`
     *  https://www.w3.org/WAI/PF/aria/roles
     */
    role?: string;
    /**
     * Set id to handle multiple container
     */
    containerId?: Id;
    /**
     * Fired when clicking inside toaster
     */
    onClick?: (event: React.MouseEvent) => void;
    /**
     * Support right to left display.
     * `Default: false`
     */
    rtl?: boolean;
    /**
     * Used to display a custom icon. Set it to `false` to prevent
     * the icons from being displayed
     */
    icon?: ToastIcon;
    /**
     * Theme to use.
     * `One of: 'light', 'dark', 'colored'`
     * `Default: 'light'`
     */
    theme?: Theme;
    /**
     * When set to `true` the built-in progress bar won't be rendered at all. Autoclose delay won't have any effect as well
     * This is only used when you want to replace the progress bar with your own.
     *
     * See https://stackblitz.com/edit/react-toastify-custom-progress-bar?file=src%2FApp.tsx for an example.
     */
    customProgressBar?: boolean;
}
interface ToastOptions<Data = unknown> extends CommonOptions {
    /**
     * An optional css class to set.
     */
    className?: ToastClassName;
    /**
     * Called when toast is mounted.
     */
    onOpen?: () => void;
    /**
     * Called when toast is unmounted.
     * The callback first argument is the closure reason.
     * It is "true" when the notification is closed by a user action like clicking on the close button.
     */
    onClose?: (reason?: boolean | string) => void;
    /**
     * An optional inline style to apply.
     */
    style?: React.CSSProperties;
    /**
     * Set the toast type.
     * `One of: 'info', 'success', 'warning', 'error', 'default'`
     */
    type?: TypeOptions;
    /**
     * Set a custom `toastId`
     */
    toastId?: Id;
    /**
     * Used during update
     */
    updateId?: Id;
    /**
     * Set the percentage for the controlled progress bar. `Value must be between 0 and 1.`
     */
    progress?: number;
    /**
     * Let you provide any data, useful when you are using your own component
     */
    data?: Data;
    /**
     * Let you specify the aria-label
     */
    ariaLabel?: string;
    /**
     * Add a delay in ms before the toast appear.
     */
    delay?: number;
    isLoading?: boolean;
}
interface ToastTransitionProps {
    isIn: boolean;
    done: () => void;
    position: ToastPosition | string;
    preventExitTransition: boolean;
    nodeRef: React.RefObject<HTMLElement>;
    children?: React.ReactNode;
    playToast(): void;
}
/**
 * @INTERNAL
 */
interface ToastProps extends ToastOptions {
    isIn: boolean;
    staleId?: Id;
    toastId: Id;
    key: Id;
    transition: ToastTransition;
    closeToast: CloseToastFunc;
    position: ToastPosition;
    children?: ToastContent;
    draggablePercent: number;
    draggableDirection?: DraggableDirection;
    progressClassName?: ToastClassName;
    className?: ToastClassName;
    deleteToast: () => void;
    theme: Theme;
    type: TypeOptions;
    collapseAll: () => void;
    stacked?: boolean;
}
type ToastItemStatus = 'added' | 'removed' | 'updated';
interface ToastItem<Data = {}> {
    content: ToastContent<Data>;
    id: Id;
    theme?: Theme;
    type?: TypeOptions;
    isLoading?: boolean;
    containerId?: Id;
    data: Data;
    icon?: ToastIcon;
    status: ToastItemStatus;
    reason?: boolean | string;
}

type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
interface NotificationCenterItem<Data = {}> extends Optional<ToastItem<Data>, 'content' | 'data' | 'status'> {
    read: boolean;
    createdAt: number;
}
type SortFn<Data> = (l: NotificationCenterItem<Data>, r: NotificationCenterItem<Data>) => number;
type FilterFn<Data = {}> = (item: NotificationCenterItem<Data>) => boolean;
interface UseNotificationCenterParams<Data = {}> {
    /**
     * initial data to rehydrate the notification center
     */
    data?: NotificationCenterItem<Data>[];
    /**
     * By default, the notifications are sorted from the newest to the oldest using
     * the `createdAt` field. Use this to provide your own sort function
     *
     * Usage:
     * ```
     * // old notifications first
     * useNotificationCenter({
     *   sort: ((l, r) => l.createdAt - r.createdAt)
     * })
     * ```
     */
    sort?: SortFn<Data>;
    /**
     * Keep the toast that meets the condition specified in the callback function.
     *
     * Usage:
     * ```
     * // keep only the toasts when hidden is set to false
     * useNotificationCenter({
     *   filter: item => item.data.hidden === false
     * })
     * ```
     */
    filter?: FilterFn<Data>;
}
interface UseNotificationCenter<Data> {
    /**
     * Contains all the notifications
     */
    notifications: NotificationCenterItem<Data>[];
    /**
     * Clear all notifications
     */
    clear(): void;
    /**
     * Mark all notification as read
     */
    markAllAsRead(): void;
    /**
     * Mark all notification as read or not.
     *
     * Usage:
     * ```
     * markAllAsRead(false) // mark all notification as not read
     *
     * markAllAsRead(true) // same as calling markAllAsRead()
     * ```
     */
    markAllAsRead(read?: boolean): void;
    /**
     * Mark one or more notifications as read.
     *
     * Usage:
     * ```
     * markAsRead("anId")
     * markAsRead(["a","list", "of", "id"])
     * ```
     */
    markAsRead(id: Id | Id[]): void;
    /**
     * Mark one or more notifications as read.The second parameter let you mark the notification as read or not.
     *
     * Usage:
     * ```
     * markAsRead("anId", false)
     * markAsRead(["a","list", "of", "id"], false)
     *
     * markAsRead("anId", true) // same as markAsRead("anId")
     * ```
     */
    markAsRead(id: Id | Id[], read?: boolean): void;
    /**
     * Remove one or more notifications
     *
     * Usage:
     * ```
     * remove("anId")
     * remove(["a","list", "of", "id"])
     * ```
     */
    remove(id: Id | Id[]): void;
    /**
     * Push a notification to the notification center.
     * Returns null when an item with the given id already exists
     *
     * Usage:
     * ```
     * const id = add({id: "id", content: "test", data: { foo: "hello" } })
     *
     * // Return the id of the notification, generate one if none provided
     * const id = add({ data: {title: "a title", text: "some text"} })
     * ```
     */
    add(item: Partial<NotificationCenterItem<Data>>): Id | null;
    /**
     * Update the notification that match the id
     * Returns null when no matching notification found
     *
     * Usage:
     * ```
     * const id = update("anId",  {content: "test", data: { foo: "hello" } })
     *
     * // It's also possible to update the id
     * const id = update("anId"m { id:"anotherOne", data: {title: "a title", text: "some text"} })
     * ```
     */
    update(id: Id, item: Partial<NotificationCenterItem<Data>>): Id | null;
    /**
     * Retrieve one or more notifications
     *
     * Usage:
     * ```
     * find("anId")
     * find(["a","list", "of", "id"])
     * ```
     */
    find(id: Id): NotificationCenterItem<Data> | undefined;
    /**
     * Retrieve one or more notifications
     *
     * Usage:
     * ```
     * find("anId")
     * find(["a","list", "of", "id"])
     * ```
     */
    find(id: Id[]): NotificationCenterItem<Data>[] | undefined;
    /**
     * Retrieve the count for unread notifications
     */
    unreadCount: number;
    /**
     * Sort notifications using the newly provided function
     *
     * Usage:
     * ```
     * // old notifications first
     * sort((l, r) => l.createdAt - r.createdAt)
     * ```
     */
    sort(sort: SortFn<Data>): void;
}
declare function useNotificationCenter<Data = {}>(params?: UseNotificationCenterParams<Data>): UseNotificationCenter<Data>;
declare function decorate<Data>(item: NotificationCenterItem<Data> | Partial<NotificationCenterItem<Data>>): NotificationCenterItem<Data>;

export { type FilterFn, type NotificationCenterItem, type SortFn, type UseNotificationCenter, type UseNotificationCenterParams, decorate, useNotificationCenter };
