import { PropTypes, CommonProperties, Direction, DirectionProperty, Required, RequiredBy } from '@zag-js/types';
import { Service, EventObject, Machine } from '@zag-js/core';
import { AnimationFrame } from '@zag-js/dom-query';

type Type = "success" | "error" | "loading" | "info" | "warning" | (string & {});
type ToastQueuePriority = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
type Placement = "top-start" | "top" | "top-end" | "bottom-start" | "bottom" | "bottom-end";
type Status = "visible" | "dismissing" | "unmounted";
interface StatusChangeDetails {
    /**
     * The status of the toast
     */
    status: Status;
    /**
     * The reason for the status change
     */
    src?: string | undefined;
}
interface ToastHeight {
    /**
     * The id of the toast
     */
    id: string;
    /**
     * The height of the toast
     */
    height: number;
}
interface ActionOptions {
    /**
     * The label of the action
     */
    label: string;
    /**
     * The function to call when the action is clicked
     */
    onClick: VoidFunction;
}
interface IntlTranslations {
    closeTriggerLabel?: string | undefined;
}
interface Options<T = any> {
    /**
     * The title of the toast.
     */
    title?: T | undefined;
    /**
     * The description of the toast.
     */
    description?: T | undefined;
    /**
     * The duration the toast will be visible
     */
    duration?: number | undefined;
    /**
     * The duration for the toast to kept alive before it is removed.
     * Useful for exit transitions.
     */
    removeDelay?: number | undefined;
    /**
     * The unique id of the toast
     */
    id?: string | undefined;
    /**
     * The type of the toast
     */
    type?: Type | undefined;
    /**
     * The priority of the toast (1 = highest, 8 = lowest)
     */
    priority?: ToastQueuePriority | undefined;
    /**
     * Function called when the toast is visible
     */
    onStatusChange?: ((details: StatusChangeDetails) => void) | undefined;
    /**
     * The action of the toast
     */
    action?: ActionOptions | undefined;
    /**
     * Whether the toast is closable
     */
    closable?: boolean | undefined;
    /**
     * The metadata of the toast
     */
    meta?: Record<string, any> | undefined;
}
interface ToastProps<T = any> extends Omit<CommonProperties, "id">, Options<T> {
    /**
     * Specifies the localized strings that identifies the accessibility elements and their states
     */
    translations?: IntlTranslations | undefined;
    /**
     * The direction of the toast
     */
    dir?: Direction | undefined;
    /**
     * The index of the toast in the group
     */
    index?: number | undefined;
    /**
     * The gap of the toast
     */
    gap?: number | undefined;
    /**
     * The parent toast group service. Required when using toast as a child of a group.
     */
    parent: Service<ToastGroupSchema>;
}
type ToastPropsWithDefault = "type" | "parent" | "duration" | "id" | "removeDelay";
type ToastSchema<O = any> = {
    props: RequiredBy<ToastProps<O>, Extract<ToastPropsWithDefault, keyof ToastProps<O>>>;
    context: {
        mounted: boolean;
        initialHeight: number;
        remainingTime: number;
    };
    computed: {
        height: number;
        heightIndex: number;
        heightBefore: number;
        frontmost: boolean;
        zIndex: number;
        shouldPersist: boolean;
    };
    refs: {
        closeTimerStartTime: number;
        lastCloseStartTimerStartTime: number;
    };
    state: "visible" | "visible:updating" | "dismissing" | "unmounted" | "visible:persist";
    tag: "visible" | "paused" | "updating";
    guard: string;
    action: string;
    effect: string;
    event: EventObject;
};
type ToastService = Service<ToastSchema>;
type ToastMachine = Machine<ToastSchema>;
interface ToastStoreProps {
    /**
     * The placement of the toast
     * @default "bottom"
     */
    placement?: Placement | undefined;
    /**
     * The maximum number of toasts. When the number of toasts exceeds this limit, the new toasts are queued.
     * @default 24
     */
    max?: number | undefined;
    /**
     * Whether to overlap the toasts
     */
    overlap?: boolean | undefined;
    /**
     * The duration of the toast.
     * By default, it is determined by the type of the toast.
     */
    duration?: number | undefined;
    /**
     * The gap between the toasts
     * @default 16
     */
    gap?: number | undefined;
    /**
     * The offset from the safe environment edge of the viewport
     * @default "1rem"
     */
    offsets?: string | Record<"left" | "right" | "bottom" | "top", string> | undefined;
    /**
     * The hotkey that will move focus to the toast group
     * @default '["altKey", "KeyT"]'
     */
    hotkey?: string[] | undefined;
    /**
     * The duration for the toast to kept alive before it is removed.
     * Useful for exit transitions.
     *
     * @default 200
     */
    removeDelay?: number | undefined;
    /**
     * Whether to pause toast when the user leaves the browser tab
     * @default false
     */
    pauseOnPageIdle?: boolean | undefined;
}
interface ToastGroupProps extends DirectionProperty, CommonProperties {
    /**
     * The store of the toast
     */
    store: ToastStore;
}
type ToastGroupSchema = {
    state: "stack" | "overlap";
    props: ToastGroupProps;
    context: {
        toasts: RequiredBy<ToastProps, Extract<ToastPropsWithDefault, keyof ToastProps>>[];
        heights: ToastHeight[];
    };
    computed: {
        count: number;
        overlap: boolean;
        placement: Placement;
    };
    refs: {
        dismissableCleanup?: VoidFunction | undefined;
        lastFocusedEl: HTMLElement | null;
        isFocusWithin: boolean;
        isPointerWithin: boolean;
        ignoreMouseTimer: AnimationFrame;
    };
    guard: string;
    effect: string;
    action: string;
    event: EventObject;
};
type ToastGroupService = Service<ToastGroupSchema>;
type ToastGroupMachine = Machine<ToastGroupSchema>;
interface ToastStore<V = any> {
    /**
     * The attributes of the toast store
     */
    attrs: Required<ToastStoreProps>;
    /**
     * Subscribe to the toast store
     */
    subscribe: (subscriber: (...args: any[]) => void) => VoidFunction;
    /**
     * Create a new toast with the given options
     */
    create: (data: Options<V>) => string;
    /**
     * Update an existing toast with new properties
     */
    update: (id: string, data: Partial<ToastProps<V>>) => string;
    /**
     * Remove a toast by its ID
     */
    remove: (id?: string) => void;
    /**
     * Dismiss a toast by its ID. If no ID is provided, dismisses all toasts
     */
    dismiss: (id?: string) => void;
    /**
     * Create an error toast with the given options
     */
    error: (data: Options<V>) => void;
    /**
     * Create a success toast with the given options
     */
    success: (data: Options<V>) => void;
    /**
     * Create an info toast with the given options
     */
    info: (data: Options<V>) => void;
    /**
     * Create a warning toast with the given options
     */
    warning: (data: Options<V>) => void;
    /**
     * Create a loading toast with the given options
     */
    loading: (data: Options<V>) => void;
    /**
     * Get all currently visible toasts
     */
    getVisibleToasts: () => Partial<ToastProps<V>>[];
    /**
     * Get the total number of toasts
     */
    getCount: () => number;
    /**
     * Create a toast that tracks a promise's state
     */
    promise: <T>(promise: Promise<T> | (() => Promise<T>), options: PromiseOptions<T, V>, shared?: Omit<Options<V>, "type">) => {
        id: string | undefined;
        unwrap: () => Promise<T>;
    } | undefined;
    /**
     * Pause a toast's auto-dismiss timer. If no ID is provided, pauses all toasts
     */
    pause: (id?: string) => void;
    /**
     * Resume a toast's auto-dismiss timer. If no ID is provided, resumes all toasts
     */
    resume: (id?: string) => void;
    /**
     * Check if a toast with the given ID is currently visible
     */
    isVisible: (id: string) => boolean;
    /**
     * Check if a toast with the given ID has been dismissed
     */
    isDismissed: (id: string) => boolean;
    /**
     * Expand all toasts to show their full content (overlap mode)
     */
    expand: VoidFunction;
    /**
     * Collapse all toasts to their compact state (overlap mode)
     */
    collapse: VoidFunction;
}
type MaybeFunction<Value, Args> = Value | ((arg: Args) => Value);
interface PromiseOptions<V, O = any> {
    loading: Omit<Options<O>, "type">;
    success?: MaybeFunction<Omit<Options<O>, "type"> & {
        type?: "success" | "warning";
    }, V> | undefined;
    error?: MaybeFunction<Omit<Options<O>, "type">, unknown> | undefined;
    finally?: (() => void | Promise<void>) | undefined;
}
interface GroupProps {
    /**
     * The human-readable label for the toast region
     */
    label?: string | undefined;
}
interface ToastGroupApi<T extends PropTypes = PropTypes, O = any> {
    /**
     * The total number of toasts
     */
    getCount: () => number;
    /**
     * The toasts
     */
    getToasts: () => ToastProps[];
    /**
     * Subscribe to the toast group
     */
    subscribe: (callback: (toasts: Options<O>[]) => void) => VoidFunction;
    getGroupProps: (options?: GroupProps) => T["element"];
}
interface ToastApi<T extends PropTypes = PropTypes, O = any> {
    /**
     * The title of the toast.
     */
    title?: O | undefined;
    /**
     * The description of the toast.
     */
    description?: O | undefined;
    /**
     * The type of the toast.
     */
    type: Type;
    /**
     * The current placement of the toast.
     */
    placement: Placement;
    /**
     * Whether the toast is visible.
     */
    visible: boolean;
    /**
     * Whether the toast should render a close button
     */
    closable: boolean;
    /**
     * Whether the toast is paused.
     */
    paused: boolean;
    /**
     * Function to pause the toast (keeping it visible).
     */
    pause: VoidFunction;
    /**
     * Function to resume the toast dismissing.
     */
    resume: VoidFunction;
    /**
     * Function to instantly dismiss the toast.
     */
    dismiss: VoidFunction;
    getRootProps: () => T["element"];
    getTitleProps: () => T["element"];
    getGhostBeforeProps: () => T["element"];
    getGhostAfterProps: () => T["element"];
    getDescriptionProps: () => T["element"];
    getCloseTriggerProps: () => T["button"];
    getActionTriggerProps: () => T["button"];
}

export type { ActionOptions, GroupProps, IntlTranslations, Options, Placement, PromiseOptions, Status, StatusChangeDetails, ToastApi, ToastGroupApi, ToastGroupMachine, ToastGroupProps, ToastGroupSchema, ToastGroupService, ToastHeight, ToastMachine, ToastProps, ToastQueuePriority, ToastSchema, ToastService, ToastStore, ToastStoreProps, Type };
