import { sleep } from 'mutate-animate';
import { message } from 'ant-design-vue';
import { MessageApi } from 'ant-design-vue/lib/message';

message.config({
    maxCount: 3
});
export function tip(
    type: Exclude<keyof MessageApi, 'open' | 'config' | 'destroy'>,
    text: string
) {
    message[type]({
        content: text,
        class: 'antdv-message'
    });
}

let num = 0;
export function requireUniqueSymbol() {
    return num++;
}

type DragFn = (x: number, y: number, e: MouseEvent | TouchEvent) => void;

type DragMap = [
    (e: MouseEvent) => void,
    (e: TouchEvent) => void,
    ((e: MouseEvent) => void)?,
    ((e: TouchEvent) => void)?
];

const dragFnMap = new Map<DragFn, DragMap>();

/**
 * 是否是移动设备
 */
export let isMobile = matchMedia('(max-width: 600px)').matches;

let alerted = false;
window.addEventListener('resize', () => {
    requestAnimationFrame(() => {
        isMobile = matchMedia('(max-width: 600px)').matches;
        checkMobile();
    });
});
checkMobile();

sleep(2000).then(() => {
    tip('info', `2.B 暂不支持竖屏游玩，手机端请考虑横屏游玩`);
});

function checkMobile() {
    if (isMobile && !alerted) {
        tip(
            'info',
            '手机端建议使用新版APP或者自带的浏览器进行游玩，并在进入游戏后开启游戏内的全屏设置游玩'
        );
        alerted = true;
    }
}

/**
 * 向一个元素添加拖拽事件
 * @param ele 目标元素，当为全局拖拽时，传入数组表示所有元素共用一个全局拖拽函数
 * @param fn 拖拽时触发的函数，传入x y和鼠标事件或点击事件
 * @param ondown 鼠标按下时执行的函数
 * @param global 是否全局拖拽，即拖拽后鼠标或手指离开元素后是否依然视为正在拖拽
 */
export function useDrag(
    ele: HTMLElement | HTMLElement[],
    fn: DragFn,
    ondown?: DragFn,
    onup?: (e: MouseEvent | TouchEvent) => void,
    global: boolean = false
) {
    const touchFn = (e: TouchEvent) => {
        fn(e.touches[0].clientX, e.touches[0].clientY, e);
    };

    const mouseFn = (e: MouseEvent) => {
        fn(e.clientX, e.clientY, e);
    };

    const mouseUp = (e: MouseEvent) => {
        const ele = global ? document : e.target;
        if (ele) {
            (ele as HTMLElement).removeEventListener('mousemove', mouseFn);
        }
        onup?.(e);
    };

    const touchUp = (e: TouchEvent) => {
        const ele = global ? document : e.target;
        if (ele) {
            (ele as HTMLElement).removeEventListener('touchmove', touchFn);
        }
        onup?.(e);
    };

    const md = (e: MouseEvent) => {
        const ele = global ? document : e.target;
        if (ele) {
            (ele as HTMLElement).addEventListener('mousemove', mouseFn);
        }
        if (ondown) ondown(e.clientX, e.clientY, e);
    };
    const td = (e: TouchEvent) => {
        const ele = global ? document : e.target;
        if (ele) {
            (ele as HTMLElement).addEventListener('touchmove', touchFn);
        }
        if (ondown) ondown(e.touches[0].clientX, e.touches[0].clientY, e);
    };

    if (ele instanceof Array) {
        ele.forEach(v => {
            v.addEventListener('mousedown', md);
            v.addEventListener('touchstart', td);
        });
    } else {
        ele.addEventListener('mousedown', md);
        ele.addEventListener('touchstart', td);
    }

    const target = global ? document : ele;

    if (target instanceof Array) {
        target.forEach(v => {
            v.addEventListener('mouseup', mouseUp);
            v.addEventListener('touchend', touchUp);
        });
    } else {
        target.addEventListener('mouseup', mouseUp as EventListener);
        target.addEventListener('touchend', touchUp as EventListener);
    }
    dragFnMap.set(fn, [mouseUp, touchUp]);
}

/**
 * 去除一个全局拖拽函数
 * @param fn 要去除的函数
 */
export function cancelGlobalDrag(fn: DragFn): void {
    const fns = dragFnMap.get(fn);
    dragFnMap.delete(fn);
    if (!fns) return;
    document.removeEventListener('mouseup', fns[0]);
    document.removeEventListener('touchend', fns[1]);
}

/**
 * 当触发滚轮时执行函数
 * @param ele 目标元素
 * @param fn 当滚轮触发时执行的函数
 */
export function useWheel(
    ele: HTMLElement,
    fn: (x: number, y: number, z: number, e: WheelEvent) => void
): void {
    ele.addEventListener('wheel', e => {
        fn(e.deltaX, e.deltaY, e.deltaZ, e);
    });
}

/**
 * 当鼠标或手指松开时执行函数
 * @param ele 目标元素
 * @param fn 当鼠标或手指松开时执行的函数
 */
export function useUp(ele: HTMLElement, fn: DragFn): void {
    ele.addEventListener('mouseup', e => {
        fn(e.clientX, e.clientY, e);
    });
    ele.addEventListener('touchend', e => {
        fn(e.touches[0].clientX, e.touches[0].clientY, e);
    });
}

/**
 * 当鼠标或手指按下时执行函数
 * @param ele 目标元素
 * @param fn 当鼠标或手指按下时执行的函数
 */
export function useDown(ele: HTMLElement, fn: DragFn): void {
    ele.addEventListener('mousedown', e => {
        fn(e.clientX, e.clientY, e);
    });
    ele.addEventListener('touchstart', e => {
        fn(e.touches[0].clientX, e.touches[0].clientY, e);
    });
}
