import { baseUniDriverFactory, isSled2, isSled3 } from '../../unidriver';
const { fireEvent = null } = process.env.NODE_ENV === 'test'
    ? (() => {
        try {
            return require('@testing-library/react');
        }
        catch { }
        return null;
    })() ||
        (() => {
            try {
                // eslint-disable-next-line import/no-extraneous-dependencies
                return require('@testing-library/dom');
            }
            catch { }
            return null;
        })()
    : {};
export function DragAndDropUniDriver(base) {
    return {
        ...baseUniDriverFactory(base),
        escapeDrag: async (source, { key: code = 'Escape' } = {}) => {
            const sourceNative = await source.getNative();
            const { page } = sourceNative;
            if (page?.evaluate) {
            }
            else if (process.env.NODE_ENV === 'test') {
                fireEvent.keyDown(sourceNative, {
                    code,
                });
            }
        },
        startKeyboardDrag: async (source) => {
            const sourceNative = await source.getNative();
            const { page } = sourceNative;
            if (page?.evaluate) {
            }
            else if (fireEvent) {
                fireEvent.keyDown(sourceNative, {
                    code: 'Enter',
                });
            }
        },
        dragOverKeyboard: async (target) => {
            const targetNative = await target.getNative();
            const { page } = targetNative;
            if (page?.evaluate) {
            }
            else if (fireEvent) {
                fireEvent.keyDown(targetNative, {
                    code: 'ArrowDown',
                });
            }
        },
        endKeyboardDrag: async (target) => {
            const targetNative = await target.getNative();
            const { page } = targetNative;
            if (page?.evaluate) {
            }
            else if (fireEvent) {
                return fireEvent.keyDown(targetNative, {
                    code: 'Enter',
                });
            }
        },
        dragStart: async (source, options = {}) => {
            const sourceNative = await source.getNative();
            if (isSled2(sourceNative)) {
                const page = options.page ?? sourceNative.page;
                const sourceBox = await sourceNative.element.boundingBox();
                await page.mouse.move(options.x ?? sourceBox.x + sourceBox.width / 2, options.y ?? sourceBox.y + sourceBox.height / 2);
                await page.mouse.down();
            }
            else if (isSled3(sourceNative)) {
                const locator = sourceNative;
                const page = options.page ?? locator.page();
                const sourceBox = await locator.boundingBox();
                if (!sourceBox) {
                    throw new Error('DragAndDropUniDriver.dragStart: source.boundingBox() returned null (element detached, zero-size, or off-screen). Drag cannot start.');
                }
                await page.mouse.move(options.x ?? sourceBox.x + sourceBox.width / 2, options.y ?? sourceBox.y + sourceBox.height / 2);
                await page.mouse.down();
            }
            else if (fireEvent) {
                fireEvent.pointerDown(sourceNative);
            }
        },
        dragMove: async () => {
            await document.dispatchEvent(new Event('mousemove'));
        },
        dragEnd: async (target, options = {}) => {
            const targetNative = await target.getNative();
            if (isSled2(targetNative)) {
                const page = options.page ?? targetNative.page;
                await page.mouse.up();
            }
            else if (isSled3(targetNative)) {
                const locator = targetNative;
                const page = options.page ?? locator.page();
                await page.mouse.up();
            }
            else if (fireEvent) {
                fireEvent.pointerUp(targetNative);
                await document.dispatchEvent(new Event('mouseup'));
            }
        },
        dragOver: async (source, target, { dragPointRatio = { x: 2, y: 2 }, dropPointRatio = { x: 2, y: 2 }, steps = 3, } = {}) => {
            const sourceRow = await source.getNative();
            const targetRow = await target.getNative();
            if (isSled2(sourceRow)) {
                const { page } = sourceRow;
                await source.hover();
                const sourceBox = await sourceRow.element.boundingBox();
                const targetBox = await targetRow.element.boundingBox();
                await page.mouse.move(sourceBox.x + sourceBox.width / dragPointRatio.x, sourceBox.y + sourceBox.height / dragPointRatio.y);
                await page.mouse.down();
                await new Promise((resolve) => setTimeout(resolve, 100));
                await page.mouse.move(targetBox.x + targetBox.width / dropPointRatio.x, targetBox.y + targetBox.height / dropPointRatio.y, { steps });
                await new Promise((resolve) => setTimeout(resolve, 100));
                await page.mouse.up();
                await new Promise((resolve) => setTimeout(resolve, 100)); // wait for drop animation to complete
            }
            else if (isSled3(sourceRow)) {
                const sourceLocator = sourceRow;
                const targetLocator = targetRow;
                const page = sourceLocator.page();
                await source.hover();
                const sourceBox = await sourceLocator.boundingBox();
                const targetBox = await targetLocator.boundingBox();
                if (!sourceBox || !targetBox) {
                    throw new Error(`DragAndDropUniDriver.dragOver: ${!sourceBox ? 'source' : 'target'}.boundingBox() returned null (element detached, zero-size, or off-screen). Drag cannot proceed.`);
                }
                await page.mouse.move(sourceBox.x + sourceBox.width / dragPointRatio.x, sourceBox.y + sourceBox.height / dragPointRatio.y);
                await page.mouse.down();
                await new Promise((resolve) => setTimeout(resolve, 100));
                await page.mouse.move(targetBox.x + targetBox.width / dropPointRatio.x, targetBox.y + targetBox.height / dropPointRatio.y, { steps });
                await new Promise((resolve) => setTimeout(resolve, 100));
                await page.mouse.up();
                await new Promise((resolve) => setTimeout(resolve, 100));
            }
            else if (fireEvent) {
                fireEvent.pointerDown(sourceRow);
                document.dispatchEvent(new Event('mousemove'));
                fireEvent.pointerUp(targetRow);
            }
        },
        moveOver: async (target, options = {}) => {
            const targetRow = await target.getNative();
            const pixels = options.pixels ?? 0;
            if (isSled2(targetRow)) {
                const page = options.page ?? targetRow.page;
                const targetBox = await targetRow.element.boundingBox();
                for (let i = 0; i < 2; i++) {
                    await page.mouse.move(Math.max(options.delta?.x ?? targetBox.x - pixels, 0), Math.max(targetBox.y + targetBox.height - pixels, 0));
                }
            }
            else if (isSled3(targetRow)) {
                const locator = targetRow;
                const page = options.page ?? locator.page();
                const targetBox = await locator.boundingBox();
                if (!targetBox) {
                    throw new Error('DragAndDropUniDriver.moveOver: target.boundingBox() returned null (element detached, zero-size, or off-screen).');
                }
                for (let i = 0; i < 2; i++) {
                    await page.mouse.move(Math.max(options.delta?.x ?? targetBox.x - pixels, 0), Math.max(targetBox.y + targetBox.height - pixels, 0));
                }
            }
            else if (fireEvent) {
                fireEvent.mouseMove(targetRow, {
                    clientX: options.delta?.x ?? 0,
                });
            }
        },
        moveAny: async (source, options) => {
            const sourceNative = await source.getNative();
            if (isSled2(sourceNative)) {
                const page = options?.page ?? sourceNative.page;
                const sourceBox = await sourceNative.element.boundingBox();
                const steps = options?.steps ?? 3;
                for (let i = steps; i >= 0; i--) {
                    await page.mouse.move((options?.x ?? sourceBox.x + sourceBox.width / 2) - i * 10, (options?.y ?? sourceBox.y + sourceBox.height / 2) -
                        (options?.vertical ? i * 10 : 0));
                    await new Promise((resolve) => setTimeout(resolve, options?.delay ?? 2000));
                }
            }
            else if (isSled3(sourceNative)) {
                const locator = sourceNative;
                const page = options?.page ?? locator.page();
                const sourceBox = await locator.boundingBox();
                if (!sourceBox) {
                    throw new Error('DragAndDropUniDriver.moveAny: source.boundingBox() returned null (element detached, zero-size, or off-screen).');
                }
                const steps = options?.steps ?? 3;
                for (let i = steps; i >= 0; i--) {
                    await page.mouse.move((options?.x ?? sourceBox.x + sourceBox.width / 2) - i * 10, (options?.y ?? sourceBox.y + sourceBox.height / 2) -
                        (options?.vertical ? i * 10 : 0));
                    await new Promise((resolve) => setTimeout(resolve, options?.delay ?? 2000));
                }
            }
        },
    };
}
//# sourceMappingURL=DragAndDrop.uni.driver.js.map