import * as chai from "chai";
import { initJSDOM } from "../../../util/jsdom.mjs";
import { ResizeObserverMock } from "../../../util/resize-observer.mjs";

const expect = chai.expect;

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

	before(function (done) {
		initJSDOM()
			.then(() => {
				import("../../../../source/components/navigation/site-navigation.mjs")
					.then((m) => {
						SiteNavigation = m.SiteNavigation;
						done();
					})
					.catch((e) => done(e));
			})
			.catch((e) => done(e));
	});

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

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

	it("should coalesce resize layout updates", function (done) {
		const OriginalResizeObserver = window.ResizeObserver;
		const originalGlobalResizeObserver = globalThis.ResizeObserver;
		const originalRequestAnimationFrame = window.requestAnimationFrame;
		const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;

		class TrackingResizeObserver extends ResizeObserverMock {
			static instances = [];

			constructor(callback) {
				super(callback);
				TrackingResizeObserver.instances.push(this);
			}
		}

		const scheduledCallbacks = [];

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

			const mocks = document.getElementById("mocks");
			mocks.innerHTML = `
				<monster-site-navigation id="nav">
					<ul>
						<li><a href="#one">One</a></li>
						<li><a href="#two">Two</a></li>
					</ul>
				</monster-site-navigation>
			`;

			const nav = document.getElementById("nav");
			const resizeObserver = TrackingResizeObserver.instances.find((observer) =>
				observer.elements.includes(nav),
			);
			expect(resizeObserver).to.exist;

			while (scheduledCallbacks.length > 0) {
				scheduledCallbacks.shift()();
			}
			resizeObserver.triggerResize([]);
			resizeObserver.triggerResize([]);

			setTimeout(() => {
				try {
					expect(scheduledCallbacks.length).to.equal(1);
					scheduledCallbacks.shift()();
					done();
				} catch (e) {
					done(e);
				} finally {
					window.ResizeObserver = OriginalResizeObserver;
					globalThis.ResizeObserver = originalGlobalResizeObserver;
					window.requestAnimationFrame = originalRequestAnimationFrame;
					globalThis.requestAnimationFrame =
						originalGlobalRequestAnimationFrame;
				}
			}, 260);
		} catch (e) {
			window.ResizeObserver = OriginalResizeObserver;
			globalThis.ResizeObserver = originalGlobalResizeObserver;
			window.requestAnimationFrame = originalRequestAnimationFrame;
			globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
			done(e);
		}
	});
});
