// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
// ┃ ██████ ██████ ██████       █      █      █      █      █ █▄  ▀███ █       ┃
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█  ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄  ▀█ █ ▀▀▀▀▀ ┃
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄   █ ▄▄▄▄▄ ┃
// ┃ █      ██████ █  ▀█▄       █ ██████      █      ███▌▐███ ███████▄ █       ┃
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
// ┃ Copyright (c) 2017, the Perspective Authors.                              ┃
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
// ┃ This file is part of the Perspective library, distributed under the terms ┃
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

import { Locator, Page } from "@playwright/test";

/** The draggable handle of the first visible inactive column. */
export const INACTIVE_DRAG =
    "#sub-columns .column-selector-column:not(.column-selector-column-hidden) .column-selector-draggable";

/** The draggable handle of the first active column. */
export const ACTIVE_DRAG =
    "#active-columns .column-selector-column .column-selector-draggable";

/** Returns the `#settings_panel` innerHTML from the viewer's shadow root. */
export async function getSettingsPanelContents(page: Page) {
    return page.evaluate(() => {
        const viewer = document.querySelector("perspective-viewer")!;
        return viewer.shadowRoot!.querySelector("#settings_panel")!.innerHTML;
    });
}

/**
 * Initiates a real browser drag from `src` to `tgt` using mouse events, without
 * completing the drop. The drag is left in-flight so the caller can snapshot the
 * intermediate dragover UI state.
 */
export async function shadowDragOver(page: Page, src: Locator, tgt: Locator) {
    const srcBox = (await src.boundingBox())!;
    const tgtBox = (await tgt.boundingBox())!;
    const srcX = srcBox.x + srcBox.width / 2;
    const srcY = srcBox.y + srcBox.height / 2;
    const tgtX = tgtBox.x + tgtBox.width / 2;
    const tgtY = tgtBox.y + tgtBox.height / 2;

    await page.mouse.move(srcX, srcY);
    await page.mouse.down();

    // Small initial move to trigger the browser's drag-start threshold.
    await page.mouse.move(srcX + 5, srcY, { steps: 2 });

    // Move to the target center, generating dragenter + dragover events.
    await page.mouse.move(tgtX, tgtY, { steps: 10 });

    // Allow Yew to process events and re-render.
    await page.waitForTimeout(100);
}

/**
 * Initiates a real browser drag from `src`, optionally hovers over
 * `wrongTgt`, then presses Escape to cancel — firing `dragend` without a
 * `drop`.
 */
export async function shadowDragCancel(
    page: Page,
    src: Locator,
    wrongTgt: Locator | null = null,
) {
    const srcBox = (await src.boundingBox())!;
    const srcX = srcBox.x + srcBox.width / 2;
    const srcY = srcBox.y + srcBox.height / 2;

    await page.evaluate(() => {
        window["dragend_resolvers"] = Promise.withResolvers();
        document.body.addEventListener("dragend", () => {
            window["dragend_resolvers"].resolve();
        });
    });

    await page.mouse.move(srcX, srcY);
    await page.mouse.down();
    await page.mouse.move(srcX + 5, srcY, { steps: 2 });

    if (wrongTgt) {
        const wrongBox = (await wrongTgt.boundingBox())!;
        await page.mouse.move(
            wrongBox.x + wrongBox.width / 2,
            wrongBox.y + wrongBox.height / 2,
            { steps: 10 },
        );
    }

    // Drag is a cruel mistress.
    await page.waitForTimeout(100);

    // Cancel the drag (fires dragend with no preceding drop).
    await page.keyboard.press("Escape");
    await page.evaluate(async () => {
        await window["dragend_resolvers"].promise;
    });
}

export async function localDrag(page: any, source: any, target: any) {
    await source.dragTo(target, { steps: 100 });
}
