import * as chai from "chai";
import { initJSDOM } from "../../../util/jsdom.mjs";

const expect = chai.expect;

describe("Sheet", function () {
	let Sheet;

	before(function (done) {
		initJSDOM()
			.then(() => {
				import("../../../../source/components/form/sheet.mjs")
					.then((m) => {
						Sheet = m.Sheet;
						done();
					})
					.catch((e) => done(e));
			})
			.catch((e) => done(e));
	});

	afterEach(() => {
		document.getElementById("mocks").innerHTML = "";
	});

	it("should register monster-sheet", function () {
		expect(document.createElement("monster-sheet")).to.be.instanceof(Sheet);
	});

	it("should coalesce column resize pointer moves", function (done) {
		const originalRequestAnimationFrame = window.requestAnimationFrame;
		const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;
		const originalCancelAnimationFrame = window.cancelAnimationFrame;
		const originalGlobalCancelAnimationFrame = globalThis.cancelAnimationFrame;
		const scheduledCallbacks = [];

		try {
			window.requestAnimationFrame = (callback) => {
				scheduledCallbacks.push(callback);
				return scheduledCallbacks.length;
			};
			globalThis.requestAnimationFrame = window.requestAnimationFrame;
			window.cancelAnimationFrame = () => {};
			globalThis.cancelAnimationFrame = window.cancelAnimationFrame;

			const mocks = document.getElementById("mocks");
			const sheet = document.createElement("monster-sheet");
			mocks.appendChild(sheet);

			setTimeout(() => {
				try {
					const grid = sheet.shadowRoot.querySelector(
						'[data-monster-role="grid"]',
					);
					const handle = sheet.shadowRoot.querySelector(
						'[data-monster-role="column-resize"]',
					);
					const header = handle.parentElement;
					grid.setPointerCapture = () => {};
					grid.releasePointerCapture = () => {};
					Object.defineProperty(header, "getBoundingClientRect", {
						configurable: true,
						value: () => ({ width: 120 }),
					});

					let resizeEvents = 0;
					sheet.addEventListener("monster-sheet-resize-column", () => {
						resizeEvents++;
					});

					const down = new Event("pointerdown", { bubbles: true });
					Object.assign(down, {
						button: 0,
						clientX: 100,
						clientY: 0,
						pointerId: 1,
					});
					handle.dispatchEvent(down);

					const firstMove = new Event("pointermove", { bubbles: true });
					Object.assign(firstMove, {
						clientX: 130,
						clientY: 0,
						pointerId: 1,
					});
					const secondMove = new Event("pointermove", { bubbles: true });
					Object.assign(secondMove, {
						clientX: 150,
						clientY: 0,
						pointerId: 1,
					});
					grid.dispatchEvent(firstMove);
					grid.dispatchEvent(secondMove);

					expect(scheduledCallbacks.length).to.equal(1);
					scheduledCallbacks.shift()();
					expect(resizeEvents).to.equal(1);

					const repeatedMove = new Event("pointermove", { bubbles: true });
					Object.assign(repeatedMove, {
						clientX: 150,
						clientY: 0,
						pointerId: 1,
					});
					grid.dispatchEvent(repeatedMove);
					scheduledCallbacks.shift()();
					expect(resizeEvents).to.equal(1);
					done();
				} catch (e) {
					done(e);
				} finally {
					window.requestAnimationFrame = originalRequestAnimationFrame;
					globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
					window.cancelAnimationFrame = originalCancelAnimationFrame;
					globalThis.cancelAnimationFrame = originalGlobalCancelAnimationFrame;
				}
			}, 0);
		} catch (e) {
			window.requestAnimationFrame = originalRequestAnimationFrame;
			globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
			window.cancelAnimationFrame = originalCancelAnimationFrame;
			globalThis.cancelAnimationFrame = originalGlobalCancelAnimationFrame;
			done(e);
		}
	});
});
