import * as vue from 'vue';
import { Ref, ComponentInternalInstance, ComputedRef, WatchSource, WritableComputedRef } from 'vue';
import { MotionState } from '@varlet/shared';

type UseEventListenerTarget = EventTarget | Ref<EventTarget | undefined | null> | (() => EventTarget);
interface UseEventListenerOptions {
    capture?: boolean;
    passive?: boolean;
}
declare function useEventListener<T extends keyof DocumentEventMap>(target: UseEventListenerTarget, type: T, listener: (event: DocumentEventMap[T]) => void, options?: UseEventListenerOptions): () => void;
declare function useEventListener(target: UseEventListenerTarget, type: string, listener: EventListener, options?: UseEventListenerOptions): () => void;

type UseClickOutsideTarget = Element | Ref<Element | undefined | null> | (() => Element);
declare function useClickOutside(target: UseClickOutsideTarget, type: string, listener: EventListener): void;

declare function onSmartMounted(hook: () => void): void;

declare function onSmartUnmounted(hook: () => void): void;

interface UseChildrenBaseProvider<C> {
    childInstances: ComponentInternalInstance[];
    collect(instance: ComponentInternalInstance, childProvider: C): void;
    clear(instance: ComponentInternalInstance, childProvider: C): void;
}
declare function useChildren<P, C>(key: symbol | string): {
    length: ComputedRef<number>;
    childProviders: C[];
    bindChildren: (parentProvider: P) => void;
};

declare function keyInProvides(key: symbol | string): boolean;
declare function useParent<P, C>(key: symbol | string): {
    index: null;
    parentProvider: null;
    bindParent: null;
} | {
    index: ComputedRef<number>;
    parentProvider: Omit<P & UseChildrenBaseProvider<C>, "clear" | "childInstances" | "collect">;
    bindParent: (childProvider: C) => void;
};

declare function onWindowResize(listener: EventListener): void;

declare function useInitialized<T>(source: WatchSource<T>, value: T): vue.Ref<boolean, boolean>;

type TouchDirection = 'horizontal' | 'vertical';
declare function useTouch(): {
    startX: vue.Ref<number, number>;
    startY: vue.Ref<number, number>;
    deltaX: vue.Ref<number, number>;
    deltaY: vue.Ref<number, number>;
    offsetX: vue.Ref<number, number>;
    offsetY: vue.Ref<number, number>;
    prevX: vue.Ref<number, number>;
    prevY: vue.Ref<number, number>;
    moveX: vue.Ref<number, number>;
    moveY: vue.Ref<number, number>;
    direction: vue.Ref<TouchDirection | undefined, TouchDirection | undefined>;
    touching: vue.Ref<boolean, boolean>;
    dragging: vue.Ref<boolean, boolean>;
    startTime: vue.Ref<number, number>;
    distance: vue.Ref<number, number>;
    resetTouch: () => void;
    startTouch: (event: TouchEvent) => void;
    moveTouch: (event: TouchEvent) => void;
    endTouch: () => void;
    isReachTop: (element: Element | Window) => boolean;
    isReachBottom: (element: Element, offset?: number) => boolean;
};

declare function useId(): vue.Ref<string | undefined, string | undefined>;

declare function useClientId(): vue.Ref<string | undefined, string | undefined>;

interface UseWindowSizeOptions {
    initialWidth?: number;
    initialHeight?: number;
}
declare function useWindowSize(options?: UseWindowSizeOptions): {
    width: vue.Ref<number, number>;
    height: vue.Ref<number, number>;
};

interface UseVModelOptions<P, K extends keyof P> {
    passive?: boolean;
    eventName?: string;
    defaultValue?: P[K];
    emit?: (event: string, value: P[K]) => void;
}
declare function useVModel<P extends Record<string, any>, K extends keyof P>(props: P, key: K, options?: UseVModelOptions<P, K>): WritableComputedRef<P[K]> | Ref<P[K]>;

interface UseMotionOptions {
    from: number | (() => number);
    to: number | (() => number);
    duration?: number | (() => number);
    timingFunction?: (v: number) => number;
    onFinished?: (value: number) => void;
}
declare function useMotion(options: UseMotionOptions): {
    value: vue.Ref<number, number>;
    state: vue.Ref<MotionState, MotionState>;
    start: () => void;
    pause: () => void;
    reset: () => void;
};

export { TouchDirection, UseChildrenBaseProvider, UseClickOutsideTarget, UseEventListenerOptions, UseEventListenerTarget, UseMotionOptions, UseVModelOptions, UseWindowSizeOptions, keyInProvides, onSmartMounted, onSmartUnmounted, onWindowResize, useChildren, useClickOutside, useClientId, useEventListener, useId, useInitialized, useMotion, useParent, useTouch, useVModel, useWindowSize };
