import { Ref, Component, App } from 'vue';

declare namespace DialogTypes {
    type Resolve = (value: T | PromiseLike<T | undefined> | undefined) => void

    type Context = { visible: Ref<boolean>; resolve: Resolve }

    type RefMaybe<T> = undefined | T | Ref<T>

    type Header = {
        content:
        | {
            title?: string
            subtitle?: string
            prependAvatar?: string
            appendAvatar?: string
            prependIcon?: string
            appendIcon?: string
            class?: string
        }
        | Component
        props?: Record<string, RefMaybe<any>>
    }

    type SeveralRef = RefMaybe<string | number | undefined>

    type Button = {
        variant?: RefMaybe<"flat" | "text" | "elevated" | "tonal" | "outlined" | "plain">
        value?: RefMaybe<any>
        disabled?: RefMaybe<boolean>
        size?: RefMaybe<string | number>
        readonly?: RefMaybe<boolean>
        height?: SeveralRef
        width?: SeveralRef
        color?: RefMaybe<string>
        maxHeight?: SeveralRef
        maxWidth?: SeveralRef
        minHeight?: SeveralRef | Ref<number>
        minWidth?: SeveralRef | Ref<number>
        loading?: RefMaybe<string | boolean>
        text?: RefMaybe<string>
        class?: RefMaybe<string>
        form?: RefMaybe<string>
        href?: RefMaybe<string>
        elevation?: SeveralRef
        prependIcon?: RefMaybe<string>
        appendIcon?: RefMaybe<string>
        onClick?: (closeDialog: (val?: any) => void, props: Record<string, any>) => void
        shortcut?: {
            value: RefMaybe<string>
            modifiers?: { click?: boolean; prevent?: boolean }
        }
        [key: string]: RefMaybe<any>
    }

    type Actions = {
        content: Component
        props?: Record<string, RefMaybe<any>>
    }

    type Body = {
        content: string | Component
        props?: { html?: boolean } & Record<string, RefMaybe<any>>
    }

    type Props = {
        header?: Header
        body?: Body
        actions?: Actions | Button[]

        class?: string
        transition?: string
        eager?: boolean
        persistent?: boolean
        scrollStrategy?: string
        closeOnContentClick?: boolean
        closeOnBack?: boolean
        fullscreen?: boolean
        height?: SeveralRef
        width?: SeveralRef
        maxHeight?: SeveralRef
        maxWidth?: SeveralRef
        minHeight?: SeveralRef
        minWidth?: SeveralRef
        opacity?: SeveralRef
        closeDelay?: SeveralRef
        openDelay?: SeveralRef
        onAfterEnter?: (() => any) | undefined
        onAfterLeave?: (() => any) | undefined
        [key: string]: any
    }

    type ActionsProps = Props & { auxActions?: Button[] }

    type Simple = Omit<Props, "actions">

    type Alert = Omit<Props, "actions"> & {
        header?: Header
        body?: Body
        action?: Button
    }

    type Confirm = Omit<Props, "actions"> & {
        acceptBtn?: Button
        cancelBtn?: Button
    }
}

declare module "vue" {
    interface ComponentCustomProperties {
        $dialog: {
            show: <T>(options: DialogTypes.Props) => Promise<T | undefined>
            alert: <T>(options: DialogTypes.Alert) => Promise<T | undefined>
            simple: <T>(options: DialogTypes.Simple) => Promise<T | undefined>
            confirm: <T>(options: DialogTypes.Confirm) => Promise<T | undefined>
        }
    }
}

declare class DialogService {
    private dialog;
    private context;
    constructor(app: App, singleton?: boolean);
    private init;
    private defaultProps;
    setSingleton(singleton?: boolean): void;
    show<T>(options: DialogTypes.Props): Promise<T | undefined>;
    simple<T>(options: DialogTypes.Simple): Promise<T>;
    alert<T>({ action: btn, ...rest }: DialogTypes.Alert): Promise<T>;
    confirm<T>({ acceptBtn, cancelBtn, ...rest }: DialogTypes.Confirm): Promise<T>;
}

declare function useDialog(): DialogService;

export { useDialog };
