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

const expect = chai.expect;
chai.use(chaiDom);

const html = `
  <div id="test1">
    <monster-control-bar id="bar">
      <input id="query" type="search">
      <select id="mode"><option>All</option></select>
      <button id="apply">Apply</button>
    </monster-control-bar>
    <monster-control-bar
      id="bar-right"
      data-monster-option-layout-alignment="right"
    ></monster-control-bar>
  </div>
`;

let ControlBar;

describe("ControlBar", function () {
  before(function (done) {
    this.timeout(5000);
    initJSDOM()
      .then(() => {
        Promise.all([
          import("../../../../source/components/form/control-bar.mjs"),
          import("../../../../source/components/form/control-bar-spacer.mjs"),
        ])
          .then((m) => {
            ControlBar = m[0].ControlBar;
            done();
          })
          .catch((e) => done(e));
      })
      .catch((e) => done(e));
  });

  beforeEach(() => {
    const mocks = document.getElementById("mocks");
    mocks.innerHTML = html;
  });

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

  it("should create a control bar element", function () {
    const bar = document.getElementById("bar");
    expect(bar).to.be.instanceof(ControlBar);
  });

  it("should keep the popper switch hidden when no controls are slotted", function (done) {
    const bar = document.getElementById("bar-right");

    setTimeout(() => {
      try {
        const switchButton = bar.shadowRoot.querySelector(
          '[data-monster-role="switch"]',
        );
        expect(switchButton).to.be.instanceof(HTMLButtonElement);
        expect(switchButton.hasAttribute("hidden")).to.be.true;
        expect(switchButton.classList.contains("hidden")).to.be.true;
        done();
      } catch (e) {
        done(e);
      }
    }, 50);
  });

  it("should default the control bar layout alignment to left", function () {
    const bar = document.getElementById("bar");
    const controlBar = bar.shadowRoot.querySelector(
      '[data-monster-role="control-bar"]',
    );

    expect(controlBar.getAttribute("data-monster-layout-alignment")).to.equal(
      "left",
    );
  });

  it("should allow configuring the control bar layout alignment to right", function (done) {
    const bar = document.getElementById("bar-right");

    setTimeout(() => {
      try {
        const controlBar = bar.shadowRoot.querySelector(
          '[data-monster-role="control-bar"]',
        );

        expect(
          controlBar.getAttribute("data-monster-layout-alignment"),
        ).to.equal("right");
        done();
      } catch (e) {
        done(e);
      }
    }, 50);
  });

  it("should update the rendered layout alignment when the option changes", async function () {
    const bar = document.getElementById("bar-right");

    await new Promise((resolve) => setTimeout(resolve, 0));

    const controlBar = bar.shadowRoot.querySelector(
      '[data-monster-role="control-bar"]',
    );

    expect(controlBar.getAttribute("data-monster-layout-alignment")).to.equal(
      "right",
    );

    bar.setOption("layout.alignment", "left");
    await new Promise((resolve) => setTimeout(resolve, 0));

    expect(controlBar.getAttribute("data-monster-layout-alignment")).to.equal(
      "left",
    );
  });

  it("should update the rendered layout alignment when the host option attribute changes", async function () {
    const bar = document.getElementById("bar");
    const controlBar = bar.shadowRoot.querySelector(
      '[data-monster-role="control-bar"]',
    );

    bar.setAttribute("data-monster-option-layout-alignment", "right");
    await new Promise((resolve) => setTimeout(resolve, 0));

    expect(bar.getOption("layout.alignment")).to.equal("right");
    expect(controlBar.getAttribute("data-monster-layout-alignment")).to.equal(
      "right",
    );
  });

  it("should dispatch one final layout changed event for rapid alignment changes", async function () {
    const bar = document.getElementById("bar-right");
    const events = [];

    await new Promise((resolve) => setTimeout(resolve, 0));

    bar.addEventListener("monster-control-bar-layout-changed", (event) => {
      events.push(event.detail);
    });

    bar.setOption("layout.alignment", "left");
    bar.setOption("layout.alignment", "right");
    bar.setOption("layout.alignment", "left");

    await new Promise((resolve) => setTimeout(resolve, 60));

    expect(events).to.have.length(1);
    expect(events[0]).to.deep.equal({
      alignment: "left",
      configuredAlignment: "left",
      stacked: false,
      stackedAlignment: undefined,
      stackedBreakpoint: undefined,
      stackedBreakpointContainer: undefined,
    });
  });

  it("should map popper position attributes to the popper placement option", function () {
    const bar = document.getElementById("bar");

    bar.setAttribute("data-monster-popper-position", "bottom");

    expect(bar.getOption("popper.placement")).to.equal("bottom");
  });

  it("should render mixed controls with joined heights and popper layout styles", function () {
    const cssText = ControlBar.getCSSStyleSheet()
      .flatMap((styleSheet) => Array.from(styleSheet.cssRules))
      .map((rule) => rule.cssText)
      .join("\n");

    expect(cssText).to.contain("--monster-control-bar-height");
    expect(cssText).to.contain("slot[name=popper]");
    expect(cssText).to.contain("align-items: stretch");
    expect(cssText).to.contain("::slotted(*) { display: flex");
    expect(cssText).to.contain("::slotted(form)");
    expect(cssText).to.contain("height: var(--monster-control-bar-height)");
    expect(cssText).to.contain(
      "border-width: var(--monster-theme-control-border-width",
    );
    expect(cssText).to.contain("appearance: none");
    expect(cssText).to.contain("--monster-select-container-overflow: hidden");
    expect(cssText).to.contain("::slotted(monster-input-group)");
    expect(cssText).to.contain("::slotted(monster-control-bar-spacer)");
    expect(cssText).to.contain(
      "--monster-control-bar-spacer-line-block-size: 60%",
    );
    expect(cssText).to.contain(
      "--monster-control-bar-spacer-line-inline-size: calc(100% - 1rem)",
    );
  });

  it("should join adjacent borders using the smaller computed border width", async function () {
    const originalRequestAnimationFrame = window.requestAnimationFrame;
    const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;

    const scheduledCallbacks = [];
    const flushFrames = async () => {
      while (scheduledCallbacks.length > 0) {
        scheduledCallbacks.shift()();
        await new Promise((resolve) => setTimeout(resolve, 0));
      }
    };

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

      const mocks = document.getElementById("mocks");
      mocks.innerHTML = `
        <div id="border-bar-wrapper">
          <monster-control-bar id="border-bar">
            <button id="wide-small-a">A</button>
            <input id="wide-small-b">
            <select id="small-small-c"><option>C</option></select>
            <button id="wide-wide-d">D</button>
          </monster-control-bar>
        </div>
      `;

      const wrapper = document.getElementById("border-bar-wrapper");
      const controls = [
        document.getElementById("wide-small-a"),
        document.getElementById("wide-small-b"),
        document.getElementById("small-small-c"),
        document.getElementById("wide-wide-d"),
      ];

      wrapper.style.boxSizing = "border-box";
      wrapper.style.width = "300px";
      Object.defineProperty(wrapper, "clientWidth", {
        configurable: true,
        value: 300,
      });

      for (const control of controls) {
        Object.defineProperty(control, "offsetWidth", {
          configurable: true,
          value: 40,
        });
        Object.defineProperty(control, "offsetHeight", {
          configurable: true,
          value: 30,
        });
        control.getBoundingClientRect = () => ({
          width: 40,
          height: 30,
          top: 0,
          right: 40,
          bottom: 30,
          left: 0,
          x: 0,
          y: 0,
          toJSON: () => {},
        });
      }

      controls[0].style.borderRightWidth = "3px";
      controls[1].style.borderLeftWidth = "2px";
      controls[1].style.borderRightWidth = "2px";
      controls[2].style.borderLeftWidth = "2px";
      controls[2].style.borderRightWidth = "3px";
      controls[3].style.borderLeftWidth = "3px";

      await flushFrames();
      await new Promise((resolve) => setTimeout(resolve, 0));
      await new Promise((resolve) => setTimeout(resolve, 0));

      expect(controls[1].style.marginLeft).to.equal("-2px");
      expect(controls[2].style.marginLeft).to.equal("-2px");
      expect(controls[3].style.marginLeft).to.equal("-3px");
    } finally {
      window.requestAnimationFrame = originalRequestAnimationFrame;
      globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
    }
  });

  it("should join borders against visible controls inside wrapper elements", async function () {
    const originalRequestAnimationFrame = window.requestAnimationFrame;
    const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;

    const scheduledCallbacks = [];
    const flushFrames = async () => {
      while (scheduledCallbacks.length > 0) {
        scheduledCallbacks.shift()();
        await new Promise((resolve) => setTimeout(resolve, 0));
      }
    };

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

      const mocks = document.getElementById("mocks");
      mocks.innerHTML = `
        <div id="wrapped-border-bar-wrapper">
          <monster-control-bar id="wrapped-border-bar">
            <button id="wrapped-border-a">A</button>
            <form id="wrapped-border-form">
              <div id="wrapped-border-b" data-monster-role="control"></div>
              <monster-input-group id="wrapped-input-group"></monster-input-group>
            </form>
          </monster-control-bar>
        </div>
      `;

      const wrapper = document.getElementById("wrapped-border-bar-wrapper");
      const button = document.getElementById("wrapped-border-a");
      const form = document.getElementById("wrapped-border-form");
      const innerControl = document.getElementById("wrapped-border-b");
      const inputGroup = document.getElementById("wrapped-input-group");

      wrapper.style.boxSizing = "border-box";
      wrapper.style.width = "300px";
      Object.defineProperty(wrapper, "clientWidth", {
        configurable: true,
        value: 300,
      });

      for (const control of [button, form]) {
        Object.defineProperty(control, "offsetWidth", {
          configurable: true,
          value: 40,
        });
        Object.defineProperty(control, "offsetHeight", {
          configurable: true,
          value: 30,
        });
        control.getBoundingClientRect = () => ({
          width: 40,
          height: 30,
          top: 0,
          right: 40,
          bottom: 30,
          left: 0,
          x: 0,
          y: 0,
          toJSON: () => {},
        });
      }

      button.style.borderRightWidth = "3px";
      innerControl.style.borderLeftWidth = "2px";

      await flushFrames();
      await new Promise((resolve) => setTimeout(resolve, 0));
      await new Promise((resolve) => setTimeout(resolve, 0));

      expect(form.style.marginLeft).to.equal("-2px");
      expect(form.style.display).to.equal("flex");
      expect(inputGroup.style.height).to.equal("100%");
      expect(inputGroup.style.boxSizing).to.equal("border-box");
      expect(inputGroup.style.flex).to.equal("1 1 auto");
    } finally {
      window.requestAnimationFrame = originalRequestAnimationFrame;
      globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
    }
  });

  it("should size inline spacer lines from adjacent border widths", async function () {
    const originalRequestAnimationFrame = window.requestAnimationFrame;
    const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;

    const scheduledCallbacks = [];
    const flushFrames = async () => {
      while (scheduledCallbacks.length > 0) {
        scheduledCallbacks.shift()();
        await new Promise((resolve) => setTimeout(resolve, 0));
      }
    };

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

      const mocks = document.getElementById("mocks");
      mocks.innerHTML = `
        <div id="spacer-border-bar-wrapper">
          <monster-control-bar id="spacer-border-bar">
            <button id="spacer-border-left">A</button>
            <monster-control-bar-spacer id="spacer-border-spacer"></monster-control-bar-spacer>
            <input id="spacer-border-right">
          </monster-control-bar>
        </div>
      `;

      const wrapper = document.getElementById("spacer-border-bar-wrapper");
      const left = document.getElementById("spacer-border-left");
      const spacer = document.getElementById("spacer-border-spacer");
      const right = document.getElementById("spacer-border-right");

      wrapper.style.boxSizing = "border-box";
      wrapper.style.width = "300px";
      Object.defineProperty(wrapper, "clientWidth", {
        configurable: true,
        value: 300,
      });

      for (const control of [left, spacer, right]) {
        Object.defineProperty(control, "offsetWidth", {
          configurable: true,
          value: 40,
        });
        Object.defineProperty(control, "offsetHeight", {
          configurable: true,
          value: 30,
        });
        control.getBoundingClientRect = () => ({
          width: 40,
          height: 30,
          top: 0,
          right: 40,
          bottom: 30,
          left: 0,
          x: 0,
          y: 0,
          toJSON: () => {},
        });
      }

      left.style.borderRightWidth = "4px";
      right.style.borderLeftWidth = "2px";

      await flushFrames();
      await new Promise((resolve) => setTimeout(resolve, 0));
      await new Promise((resolve) => setTimeout(resolve, 0));

      expect(
        spacer.style.getPropertyValue(
          "--monster-control-bar-spacer-line-inline-size",
        ),
      ).to.equal("4px");
      expect(spacer.style.marginLeft).to.equal("");
      expect(right.style.marginLeft).to.equal("");
    } finally {
      window.requestAnimationFrame = originalRequestAnimationFrame;
      globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
    }
  });

  it("should size popper spacer lines from adjacent border widths", async function () {
    const originalRequestAnimationFrame = window.requestAnimationFrame;
    const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;

    const scheduledCallbacks = [];
    const flushFrames = async () => {
      while (scheduledCallbacks.length > 0) {
        scheduledCallbacks.shift()();
        await new Promise((resolve) => setTimeout(resolve, 0));
      }
    };

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

      const mocks = document.getElementById("mocks");
      mocks.innerHTML = `
        <div id="popper-spacer-border-bar-wrapper">
          <monster-control-bar id="popper-spacer-border-bar">
            <button id="popper-spacer-border-top">A</button>
            <monster-control-bar-spacer id="popper-spacer-border-spacer"></monster-control-bar-spacer>
            <input id="popper-spacer-border-bottom">
          </monster-control-bar>
        </div>
      `;

      const wrapper = document.getElementById("popper-spacer-border-bar-wrapper");
      const top = document.getElementById("popper-spacer-border-top");
      const spacer = document.getElementById("popper-spacer-border-spacer");
      const bottom = document.getElementById("popper-spacer-border-bottom");

      wrapper.style.boxSizing = "border-box";
      wrapper.style.width = "1px";
      Object.defineProperty(wrapper, "clientWidth", {
        configurable: true,
        value: 1,
      });

      for (const control of [top, spacer, bottom]) {
        Object.defineProperty(control, "offsetWidth", {
          configurable: true,
          value: 40,
        });
        Object.defineProperty(control, "offsetHeight", {
          configurable: true,
          value: 30,
        });
        control.getBoundingClientRect = () => ({
          width: 40,
          height: 30,
          top: 0,
          right: 40,
          bottom: 30,
          left: 0,
          x: 0,
          y: 0,
          toJSON: () => {},
        });
      }

      top.style.borderBottomWidth = "2px";
      bottom.style.borderTopWidth = "5px";

      await flushFrames();
      await new Promise((resolve) => setTimeout(resolve, 0));
      await new Promise((resolve) => setTimeout(resolve, 0));

      expect(spacer.getAttribute("slot")).to.equal("popper");
      expect(
        spacer.style.getPropertyValue(
          "--monster-control-bar-spacer-line-block-size",
        ),
      ).to.equal("5px");
      expect(spacer.style.marginTop).to.equal("");
      expect(bottom.style.marginTop).to.equal("");
    } finally {
      window.requestAnimationFrame = originalRequestAnimationFrame;
      globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
    }
  });

  it("should move overflowing mixed controls into the popper", async function () {
    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 = [];
    const flushFrames = async () => {
      while (scheduledCallbacks.length > 0) {
        scheduledCallbacks.shift()();
        await new Promise((resolve) => setTimeout(resolve, 0));
      }
    };

    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 = `
        <div id="control-bar-wrapper">
          <monster-control-bar
            id="overflow-bar"
            data-monster-option-layout-alignment="right"
            data-monster-option-layout-stacked-alignment="left"
          >
            <input id="overflow-input" type="search">
            <select id="overflow-select"><option>One</option></select>
            <button id="overflow-button">Run</button>
          </monster-control-bar>
        </div>
      `;

      const wrapper = document.getElementById("control-bar-wrapper");
      const bar = document.getElementById("overflow-bar");
      const controls = [
        document.getElementById("overflow-input"),
        document.getElementById("overflow-select"),
        document.getElementById("overflow-button"),
      ];

      wrapper.style.boxSizing = "border-box";
      wrapper.style.width = "90px";
      Object.defineProperty(wrapper, "clientWidth", {
        configurable: true,
        value: 90,
      });

      for (const control of controls) {
        Object.defineProperty(control, "offsetWidth", {
          configurable: true,
          value: 50,
        });
        Object.defineProperty(control, "offsetHeight", {
          configurable: true,
          value: 30,
        });
        control.getBoundingClientRect = () => ({
          width: 50,
          height: 30,
          top: 0,
          right: 50,
          bottom: 30,
          left: 0,
          x: 0,
          y: 0,
          toJSON: () => {},
        });
      }

      const switchButton = bar.shadowRoot.querySelector(
        '[data-monster-role="switch"]',
      );
      Object.defineProperty(switchButton, "offsetWidth", {
        configurable: true,
        value: 20,
      });
      const controlBar = bar.shadowRoot.querySelector(
        '[data-monster-role="control-bar"]',
      );

      await flushFrames();
      await new Promise((resolve) => setTimeout(resolve, 0));
      await new Promise((resolve) => setTimeout(resolve, 0));

      expect(switchButton.hasAttribute("hidden")).to.be.false;
      expect(controlBar.getAttribute("data-monster-layout-stacked")).to.equal(
        "true",
      );
      expect(controlBar.getAttribute("data-monster-layout-alignment")).to.equal(
        "left",
      );
      expect(document.getElementById("overflow-input").hasAttribute("slot")).to
        .be.false;
      expect(document.getElementById("overflow-select").getAttribute("slot")).to
        .equal("popper");
      expect(document.getElementById("overflow-button").getAttribute("slot")).to
        .equal("popper");
    } finally {
      window.ResizeObserver = OriginalResizeObserver;
      globalThis.ResizeObserver = originalGlobalResizeObserver;
      window.requestAnimationFrame = originalRequestAnimationFrame;
      globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
    }
  });

  it("should apply stacked alignment below the configured container breakpoint without overflow", async function () {
    const originalRequestAnimationFrame = window.requestAnimationFrame;
    const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;

    const scheduledCallbacks = [];
    const flushFrames = async () => {
      while (scheduledCallbacks.length > 0) {
        scheduledCallbacks.shift()();
        await new Promise((resolve) => setTimeout(resolve, 0));
      }
    };

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

      const mocks = document.getElementById("mocks");
      mocks.innerHTML = `
        <div id="breakpoint-bar-wrapper">
          <monster-control-bar
            id="breakpoint-bar"
            data-monster-option-layout-alignment="right"
            data-monster-option-layout-stacked-alignment="left"
            data-monster-option-layout-stacked-breakpoint="100px"
          >
            <button id="breakpoint-button">Run</button>
          </monster-control-bar>
        </div>
      `;

      const wrapper = document.getElementById("breakpoint-bar-wrapper");
      const button = document.getElementById("breakpoint-button");
      const bar = document.getElementById("breakpoint-bar");
      const controlBar = bar.shadowRoot.querySelector(
        '[data-monster-role="control-bar"]',
      );
      const switchButton = bar.shadowRoot.querySelector(
        '[data-monster-role="switch"]',
      );

      wrapper.style.boxSizing = "border-box";
      Object.defineProperty(wrapper, "clientWidth", {
        configurable: true,
        value: 90,
      });
      Object.defineProperty(button, "offsetWidth", {
        configurable: true,
        value: 40,
      });
      Object.defineProperty(button, "offsetHeight", {
        configurable: true,
        value: 30,
      });
      button.getBoundingClientRect = () => ({
        width: 40,
        height: 30,
        top: 0,
        right: 40,
        bottom: 30,
        left: 0,
        x: 0,
        y: 0,
        toJSON: () => {},
      });
      Object.defineProperty(switchButton, "offsetWidth", {
        configurable: true,
        value: 20,
      });

      expect(controlBar.style.opacity).to.equal("0");

      await flushFrames();
      await new Promise((resolve) => setTimeout(resolve, 0));
      await new Promise((resolve) => setTimeout(resolve, 0));

      expect(switchButton.hasAttribute("hidden")).to.be.true;
      expect(button.hasAttribute("slot")).to.be.false;
      expect(controlBar.style.opacity).to.equal("");
      expect(controlBar.getAttribute("data-monster-layout-stacked")).to.equal(
        "true",
      );
      expect(controlBar.getAttribute("data-monster-layout-alignment")).to.equal(
        "left",
      );
    } finally {
      window.requestAnimationFrame = originalRequestAnimationFrame;
      globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
    }
  });

  it("should keep the overflow switch stable across the switch-width threshold", async function () {
    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 = [];
    const flushFrames = async () => {
      while (scheduledCallbacks.length > 0) {
        scheduledCallbacks.shift()();
        await new Promise((resolve) => setTimeout(resolve, 0));
      }
    };

    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 = `
        <div id="threshold-bar-wrapper">
          <monster-control-bar id="threshold-bar">
            <button id="threshold-one">One</button>
            <button id="threshold-two">Two</button>
            <button id="threshold-three">Three</button>
          </monster-control-bar>
        </div>
      `;

      const wrapper = document.getElementById("threshold-bar-wrapper");
      const bar = document.getElementById("threshold-bar");
      const buttons = [
        document.getElementById("threshold-one"),
        document.getElementById("threshold-two"),
        document.getElementById("threshold-three"),
      ];
      let wrapperWidth = 90;

      wrapper.style.boxSizing = "border-box";
      Object.defineProperty(wrapper, "clientWidth", {
        configurable: true,
        get: () => wrapperWidth,
      });

      for (const button of buttons) {
        Object.defineProperty(button, "offsetWidth", {
          configurable: true,
          value: 50,
        });
        Object.defineProperty(button, "offsetHeight", {
          configurable: true,
          value: 30,
        });
        button.getBoundingClientRect = () => ({
          width: 50,
          height: 30,
          top: 0,
          right: 50,
          bottom: 30,
          left: 0,
          x: 0,
          y: 0,
          toJSON: () => {},
        });
      }

      const switchButton = bar.shadowRoot.querySelector(
        '[data-monster-role="switch"]',
      );
      Object.defineProperty(switchButton, "offsetWidth", {
        configurable: true,
        value: 20,
      });

      await flushFrames();
      expect(switchButton.hasAttribute("hidden")).to.be.false;

      const resizeObserver = TrackingResizeObserver.instances.find((observer) =>
        observer.elements.includes(wrapper),
      );
      expect(resizeObserver).to.exist;

      wrapperWidth = 155;
      resizeObserver.triggerResize([{ target: wrapper }]);
      await flushFrames();
      expect(switchButton.hasAttribute("hidden")).to.be.false;
      expect(document.getElementById("threshold-three").getAttribute("slot")).to
        .equal("popper");

      wrapperWidth = 175;
      resizeObserver.triggerResize([{ target: wrapper }]);
      await flushFrames();
      expect(switchButton.hasAttribute("hidden")).to.be.false;
      expect(document.getElementById("threshold-three").getAttribute("slot")).to
        .equal("popper");

      wrapperWidth = 190;
      resizeObserver.triggerResize([{ target: wrapper }]);
      await flushFrames();
      expect(switchButton.hasAttribute("hidden")).to.be.true;
      expect(document.getElementById("threshold-three").hasAttribute("slot")).to
        .be.false;

      wrapperWidth = 160;
      resizeObserver.triggerResize([{ target: wrapper }]);
      await flushFrames();
      expect(switchButton.hasAttribute("hidden")).to.be.false;
      expect(document.getElementById("threshold-three").getAttribute("slot")).to
        .equal("popper");
    } finally {
      window.ResizeObserver = OriginalResizeObserver;
      globalThis.ResizeObserver = originalGlobalResizeObserver;
      window.requestAnimationFrame = originalRequestAnimationFrame;
      globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
    }
  });

  it("should move spacers with adjacent overflow controls", async function () {
    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 = [];
    const flushFrames = async () => {
      while (scheduledCallbacks.length > 0) {
        scheduledCallbacks.shift()();
        await new Promise((resolve) => setTimeout(resolve, 0));
      }
    };

    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 = `
        <div id="spacer-overflow-wrapper">
          <monster-control-bar id="spacer-overflow-bar">
            <button id="spacer-overflow-one">One</button>
            <monster-control-bar-spacer id="spacer-overflow-spacer-one"></monster-control-bar-spacer>
            <button id="spacer-overflow-two">Two</button>
            <monster-control-bar-spacer id="spacer-overflow-spacer-two"></monster-control-bar-spacer>
            <button id="spacer-overflow-three">Three</button>
          </monster-control-bar>
        </div>
      `;

      const wrapper = document.getElementById("spacer-overflow-wrapper");
      const bar = document.getElementById("spacer-overflow-bar");
      const sizes = new Map([
        ["spacer-overflow-one", 50],
        ["spacer-overflow-spacer-one", 10],
        ["spacer-overflow-two", 100],
        ["spacer-overflow-spacer-two", 10],
        ["spacer-overflow-three", 50],
      ]);

      wrapper.style.boxSizing = "border-box";
      Object.defineProperty(wrapper, "clientWidth", {
        configurable: true,
        value: 100,
      });

      for (const [id, width] of sizes) {
        const element = document.getElementById(id);
        Object.defineProperty(element, "offsetWidth", {
          configurable: true,
          value: width,
        });
        Object.defineProperty(element, "offsetHeight", {
          configurable: true,
          value: 30,
        });
        element.getBoundingClientRect = () => ({
          width,
          height: 30,
          top: 0,
          right: width,
          bottom: 30,
          left: 0,
          x: 0,
          y: 0,
          toJSON: () => {},
        });
      }

      const switchButton = bar.shadowRoot.querySelector(
        '[data-monster-role="switch"]',
      );
      Object.defineProperty(switchButton, "offsetWidth", {
        configurable: true,
        value: 20,
      });

      await flushFrames();
      expect(document.getElementById("spacer-overflow-one").hasAttribute("slot"))
        .to.be.false;
      expect(
        document.getElementById("spacer-overflow-spacer-one").getAttribute("slot"),
      ).to.equal("popper");
      expect(document.getElementById("spacer-overflow-two").getAttribute("slot"))
        .to.equal("popper");
      expect(
        document.getElementById("spacer-overflow-spacer-two").getAttribute("slot"),
      ).to.equal("popper");
      expect(
        document.getElementById("spacer-overflow-three").getAttribute("slot"),
      ).to.equal("popper");

      const resizeObserver = TrackingResizeObserver.instances.find((observer) =>
        observer.elements.includes(wrapper),
      );
      expect(resizeObserver).to.exist;

      resizeObserver.triggerResize([{ target: wrapper }]);
      await flushFrames();
      expect(
        document.getElementById("spacer-overflow-spacer-one").getAttribute("slot"),
      ).to.equal("popper");
      expect(
        document.getElementById("spacer-overflow-spacer-two").getAttribute("slot"),
      ).to.equal("popper");
    } finally {
      window.ResizeObserver = OriginalResizeObserver;
      globalThis.ResizeObserver = originalGlobalResizeObserver;
      window.requestAnimationFrame = originalRequestAnimationFrame;
      globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
    }
  });

  it("should keep overflow as an ordered suffix when later controls would fit", async function () {
    const originalRequestAnimationFrame = window.requestAnimationFrame;
    const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;

    const scheduledCallbacks = [];
    const flushFrames = async () => {
      while (scheduledCallbacks.length > 0) {
        scheduledCallbacks.shift()();
        await new Promise((resolve) => setTimeout(resolve, 0));
      }
    };

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

      const mocks = document.getElementById("mocks");
      mocks.innerHTML = `
        <div id="ordered-overflow-wrapper">
          <monster-control-bar id="ordered-overflow-bar">
            <button id="ordered-overflow-one">One</button>
            <button id="ordered-overflow-wide">Wide</button>
            <button id="ordered-overflow-small">Small</button>
          </monster-control-bar>
        </div>
      `;

      const wrapper = document.getElementById("ordered-overflow-wrapper");
      const bar = document.getElementById("ordered-overflow-bar");
      const sizes = new Map([
        ["ordered-overflow-one", 50],
        ["ordered-overflow-wide", 100],
        ["ordered-overflow-small", 20],
      ]);

      wrapper.style.boxSizing = "border-box";
      Object.defineProperty(wrapper, "clientWidth", {
        configurable: true,
        value: 90,
      });

      for (const [id, width] of sizes) {
        const element = document.getElementById(id);
        Object.defineProperty(element, "offsetWidth", {
          configurable: true,
          value: width,
        });
        Object.defineProperty(element, "offsetHeight", {
          configurable: true,
          value: 30,
        });
        element.getBoundingClientRect = () => ({
          width,
          height: 30,
          top: 0,
          right: width,
          bottom: 30,
          left: 0,
          x: 0,
          y: 0,
          toJSON: () => {},
        });
      }

      const switchButton = bar.shadowRoot.querySelector(
        '[data-monster-role="switch"]',
      );
      Object.defineProperty(switchButton, "offsetWidth", {
        configurable: true,
        value: 20,
      });

      await flushFrames();

      expect(document.getElementById("ordered-overflow-one").hasAttribute("slot"))
        .to.be.false;
      expect(document.getElementById("ordered-overflow-wide").getAttribute("slot"))
        .to.equal("popper");
      expect(document.getElementById("ordered-overflow-small").getAttribute("slot"))
        .to.equal("popper");
    } finally {
      window.requestAnimationFrame = originalRequestAnimationFrame;
      globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
    }
  });

  it("should keep the previous overflow boundary while the switch remains visible", async function () {
    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 = [];
    const flushFrames = async () => {
      while (scheduledCallbacks.length > 0) {
        scheduledCallbacks.shift()();
        await new Promise((resolve) => setTimeout(resolve, 0));
      }
    };

    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 = `
        <div id="sticky-overflow-wrapper">
          <monster-control-bar id="sticky-overflow-bar">
            <button id="sticky-overflow-one">One</button>
            <button id="sticky-overflow-wide">Wide</button>
            <button id="sticky-overflow-small">Small</button>
          </monster-control-bar>
        </div>
      `;

      const wrapper = document.getElementById("sticky-overflow-wrapper");
      const bar = document.getElementById("sticky-overflow-bar");
      let wrapperWidth = 90;
      const sizes = new Map([
        ["sticky-overflow-one", 50],
        ["sticky-overflow-wide", 100],
        ["sticky-overflow-small", 20],
      ]);

      wrapper.style.boxSizing = "border-box";
      Object.defineProperty(wrapper, "clientWidth", {
        configurable: true,
        get: () => wrapperWidth,
      });

      for (const [id, width] of sizes) {
        const element = document.getElementById(id);
        Object.defineProperty(element, "offsetWidth", {
          configurable: true,
          value: width,
        });
        Object.defineProperty(element, "offsetHeight", {
          configurable: true,
          value: 30,
        });
        element.getBoundingClientRect = () => ({
          width,
          height: 30,
          top: 0,
          right: width,
          bottom: 30,
          left: 0,
          x: 0,
          y: 0,
          toJSON: () => {},
        });
      }

      const switchButton = bar.shadowRoot.querySelector(
        '[data-monster-role="switch"]',
      );
      Object.defineProperty(switchButton, "offsetWidth", {
        configurable: true,
        value: 20,
      });

      await flushFrames();
      expect(document.getElementById("sticky-overflow-wide").getAttribute("slot"))
        .to.equal("popper");
      expect(document.getElementById("sticky-overflow-small").getAttribute("slot"))
        .to.equal("popper");

      const resizeObserver = TrackingResizeObserver.instances.find((observer) =>
        observer.elements.includes(wrapper),
      );
      expect(resizeObserver).to.exist;

      wrapperWidth = 190;
      resizeObserver.triggerResize([{ target: wrapper }]);
      await flushFrames();
      expect(switchButton.hasAttribute("hidden")).to.be.false;
      expect(document.getElementById("sticky-overflow-wide").getAttribute("slot"))
        .to.equal("popper");
      expect(document.getElementById("sticky-overflow-small").getAttribute("slot"))
        .to.equal("popper");

      wrapperWidth = 220;
      resizeObserver.triggerResize([{ target: wrapper }]);
      await flushFrames();
      expect(switchButton.hasAttribute("hidden")).to.be.true;
      expect(document.getElementById("sticky-overflow-wide").hasAttribute("slot"))
        .to.be.false;
      expect(document.getElementById("sticky-overflow-small").hasAttribute("slot"))
        .to.be.false;
    } finally {
      window.ResizeObserver = OriginalResizeObserver;
      globalThis.ResizeObserver = originalGlobalResizeObserver;
      window.requestAnimationFrame = originalRequestAnimationFrame;
      globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
    }
  });

  it("should match the stacked breakpoint when the content-box container width is a css string", async function () {
    const originalRequestAnimationFrame = window.requestAnimationFrame;
    const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;

    const scheduledCallbacks = [];
    const flushFrames = async () => {
      while (scheduledCallbacks.length > 0) {
        scheduledCallbacks.shift()();
        await new Promise((resolve) => setTimeout(resolve, 0));
      }
    };

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

      const mocks = document.getElementById("mocks");
      mocks.innerHTML = `
        <div id="content-box-breakpoint-wrapper">
          <monster-control-bar
            id="content-box-breakpoint-bar"
            data-monster-option-layout-alignment="right"
            data-monster-option-layout-stacked-alignment="left"
            data-monster-option-layout-stacked-breakpoint="480px"
          >
            <button id="content-box-breakpoint-button">Run</button>
          </monster-control-bar>
        </div>
      `;

      const wrapper = document.getElementById(
        "content-box-breakpoint-wrapper",
      );
      const button = document.getElementById("content-box-breakpoint-button");
      const bar = document.getElementById("content-box-breakpoint-bar");
      const controlBar = bar.shadowRoot.querySelector(
        '[data-monster-role="control-bar"]',
      );
      const switchButton = bar.shadowRoot.querySelector(
        '[data-monster-role="switch"]',
      );

      wrapper.style.boxSizing = "content-box";
      wrapper.style.width = "350.156px";
      Object.defineProperty(button, "offsetWidth", {
        configurable: true,
        value: 40,
      });
      Object.defineProperty(button, "offsetHeight", {
        configurable: true,
        value: 30,
      });
      button.getBoundingClientRect = () => ({
        width: 40,
        height: 30,
        top: 0,
        right: 40,
        bottom: 30,
        left: 0,
        x: 0,
        y: 0,
        toJSON: () => {},
      });
      Object.defineProperty(switchButton, "offsetWidth", {
        configurable: true,
        value: 20,
      });

      await flushFrames();
      await new Promise((resolve) => setTimeout(resolve, 0));
      await new Promise((resolve) => setTimeout(resolve, 0));

      expect(switchButton.hasAttribute("hidden")).to.be.true;
      expect(button.hasAttribute("slot")).to.be.false;
      expect(controlBar.getAttribute("data-monster-layout-stacked")).to.equal(
        "true",
      );
      expect(controlBar.getAttribute("data-monster-layout-alignment")).to.equal(
        "left",
      );
    } finally {
      window.requestAnimationFrame = originalRequestAnimationFrame;
      globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
    }
  });

  it("should keep the configured alignment when the reference container is above the stacked breakpoint", async function () {
    const originalRequestAnimationFrame = window.requestAnimationFrame;
    const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;

    const scheduledCallbacks = [];
    const flushFrames = async () => {
      while (scheduledCallbacks.length > 0) {
        scheduledCallbacks.shift()();
        await new Promise((resolve) => setTimeout(resolve, 0));
      }
    };

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

      const mocks = document.getElementById("mocks");
      mocks.innerHTML = `
        <div id="headline-wide" class="page-headline-bar">
          <div id="headline-wide-control-column">
            <monster-control-bar
              id="headline-wide-bar"
              data-monster-option-layout-alignment="right"
              data-monster-option-layout-stacked-alignment="left"
              data-monster-option-layout-stacked-breakpoint="480px"
              data-monster-option-layout-stacked-breakpoint-container=".page-headline-bar"
            >
              <button id="headline-wide-button">Run</button>
            </monster-control-bar>
          </div>
        </div>
      `;

      const headline = document.getElementById("headline-wide");
      const column = document.getElementById("headline-wide-control-column");
      const button = document.getElementById("headline-wide-button");
      const bar = document.getElementById("headline-wide-bar");
      const controlBar = bar.shadowRoot.querySelector(
        '[data-monster-role="control-bar"]',
      );

      headline.style.boxSizing = "border-box";
      Object.defineProperty(headline, "clientWidth", {
        configurable: true,
        value: 640,
      });
      column.style.boxSizing = "border-box";
      Object.defineProperty(column, "clientWidth", {
        configurable: true,
        value: 459.469,
      });
      Object.defineProperty(button, "offsetWidth", {
        configurable: true,
        value: 40,
      });
      Object.defineProperty(button, "offsetHeight", {
        configurable: true,
        value: 30,
      });
      button.getBoundingClientRect = () => ({
        width: 40,
        height: 30,
        top: 0,
        right: 40,
        bottom: 30,
        left: 0,
        x: 0,
        y: 0,
        toJSON: () => {},
      });

      await flushFrames();
      await new Promise((resolve) => setTimeout(resolve, 0));
      await new Promise((resolve) => setTimeout(resolve, 0));

      expect(controlBar.getAttribute("data-monster-layout-stacked")).to.equal(
        "false",
      );
      expect(controlBar.getAttribute("data-monster-layout-alignment")).to.equal(
        "right",
      );
    } finally {
      window.requestAnimationFrame = originalRequestAnimationFrame;
      globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
    }
  });

  it("should apply stacked alignment when the reference container is below the stacked breakpoint", async function () {
    const originalRequestAnimationFrame = window.requestAnimationFrame;
    const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;

    const scheduledCallbacks = [];
    const flushFrames = async () => {
      while (scheduledCallbacks.length > 0) {
        scheduledCallbacks.shift()();
        await new Promise((resolve) => setTimeout(resolve, 0));
      }
    };

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

      const mocks = document.getElementById("mocks");
      mocks.innerHTML = `
        <div id="headline-narrow" class="page-headline-bar">
          <div id="headline-narrow-control-column">
            <monster-control-bar
              id="headline-narrow-bar"
              data-monster-option-layout-alignment="right"
              data-monster-option-layout-stacked-alignment="left"
              data-monster-option-layout-stacked-breakpoint="480px"
              data-monster-option-layout-stacked-breakpoint-container=".page-headline-bar"
            >
              <button id="headline-narrow-button">Run</button>
            </monster-control-bar>
          </div>
        </div>
      `;

      const headline = document.getElementById("headline-narrow");
      const column = document.getElementById("headline-narrow-control-column");
      const button = document.getElementById("headline-narrow-button");
      const bar = document.getElementById("headline-narrow-bar");
      const controlBar = bar.shadowRoot.querySelector(
        '[data-monster-role="control-bar"]',
      );

      headline.style.boxSizing = "border-box";
      Object.defineProperty(headline, "clientWidth", {
        configurable: true,
        value: 350,
      });
      column.style.boxSizing = "border-box";
      Object.defineProperty(column, "clientWidth", {
        configurable: true,
        value: 459.469,
      });
      Object.defineProperty(button, "offsetWidth", {
        configurable: true,
        value: 40,
      });
      Object.defineProperty(button, "offsetHeight", {
        configurable: true,
        value: 30,
      });
      button.getBoundingClientRect = () => ({
        width: 40,
        height: 30,
        top: 0,
        right: 40,
        bottom: 30,
        left: 0,
        x: 0,
        y: 0,
        toJSON: () => {},
      });

      await flushFrames();
      await new Promise((resolve) => setTimeout(resolve, 0));
      await new Promise((resolve) => setTimeout(resolve, 0));

      expect(controlBar.getAttribute("data-monster-layout-stacked")).to.equal(
        "true",
      );
      expect(controlBar.getAttribute("data-monster-layout-alignment")).to.equal(
        "left",
      );
    } finally {
      window.requestAnimationFrame = originalRequestAnimationFrame;
      globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
    }
  });

  it("should fall back to the control bar width when the breakpoint container selector cannot resolve", async function () {
    const originalRequestAnimationFrame = window.requestAnimationFrame;
    const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;

    const scheduledCallbacks = [];
    const flushFrames = async () => {
      while (scheduledCallbacks.length > 0) {
        scheduledCallbacks.shift()();
        await new Promise((resolve) => setTimeout(resolve, 0));
      }
    };

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

      const mocks = document.getElementById("mocks");
      mocks.innerHTML = `
        <div id="missing-reference-wrapper">
          <monster-control-bar
            id="missing-reference-bar"
            data-monster-option-layout-alignment="right"
            data-monster-option-layout-stacked-alignment="left"
            data-monster-option-layout-stacked-breakpoint="480px"
            data-monster-option-layout-stacked-breakpoint-container=".missing-reference"
          >
            <button id="missing-reference-button">Run</button>
          </monster-control-bar>
        </div>
      `;

      const wrapper = document.getElementById("missing-reference-wrapper");
      const button = document.getElementById("missing-reference-button");
      const bar = document.getElementById("missing-reference-bar");
      const controlBar = bar.shadowRoot.querySelector(
        '[data-monster-role="control-bar"]',
      );

      wrapper.style.boxSizing = "border-box";
      Object.defineProperty(wrapper, "clientWidth", {
        configurable: true,
        value: 350,
      });
      Object.defineProperty(button, "offsetWidth", {
        configurable: true,
        value: 40,
      });
      Object.defineProperty(button, "offsetHeight", {
        configurable: true,
        value: 30,
      });
      button.getBoundingClientRect = () => ({
        width: 40,
        height: 30,
        top: 0,
        right: 40,
        bottom: 30,
        left: 0,
        x: 0,
        y: 0,
        toJSON: () => {},
      });

      await flushFrames();
      await new Promise((resolve) => setTimeout(resolve, 0));
      await new Promise((resolve) => setTimeout(resolve, 0));

      expect(controlBar.getAttribute("data-monster-layout-stacked")).to.equal(
        "true",
      );
      expect(controlBar.getAttribute("data-monster-layout-alignment")).to.equal(
        "left",
      );
    } finally {
      window.requestAnimationFrame = originalRequestAnimationFrame;
      globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
    }
  });

  it("should fall back without throwing when the breakpoint container selector is invalid", async function () {
    const originalRequestAnimationFrame = window.requestAnimationFrame;
    const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;

    const scheduledCallbacks = [];
    const flushFrames = async () => {
      while (scheduledCallbacks.length > 0) {
        scheduledCallbacks.shift()();
        await new Promise((resolve) => setTimeout(resolve, 0));
      }
    };

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

      const mocks = document.getElementById("mocks");
      mocks.innerHTML = `
        <div id="invalid-reference-wrapper">
          <monster-control-bar
            id="invalid-reference-bar"
            data-monster-option-layout-alignment="right"
            data-monster-option-layout-stacked-alignment="left"
            data-monster-option-layout-stacked-breakpoint="480px"
          >
            <button id="invalid-reference-button">Run</button>
          </monster-control-bar>
        </div>
      `;

      const wrapper = document.getElementById("invalid-reference-wrapper");
      const button = document.getElementById("invalid-reference-button");
      const bar = document.getElementById("invalid-reference-bar");
      const controlBar = bar.shadowRoot.querySelector(
        '[data-monster-role="control-bar"]',
      );

      bar.setOption("layout.stackedBreakpointContainer", "[");
      wrapper.style.boxSizing = "border-box";
      Object.defineProperty(wrapper, "clientWidth", {
        configurable: true,
        value: 350,
      });
      Object.defineProperty(button, "offsetWidth", {
        configurable: true,
        value: 40,
      });
      Object.defineProperty(button, "offsetHeight", {
        configurable: true,
        value: 30,
      });
      button.getBoundingClientRect = () => ({
        width: 40,
        height: 30,
        top: 0,
        right: 40,
        bottom: 30,
        left: 0,
        x: 0,
        y: 0,
        toJSON: () => {},
      });

      await flushFrames();
      await new Promise((resolve) => setTimeout(resolve, 0));
      await new Promise((resolve) => setTimeout(resolve, 0));

      expect(controlBar.getAttribute("data-monster-layout-stacked")).to.equal(
        "true",
      );
      expect(controlBar.getAttribute("data-monster-layout-alignment")).to.equal(
        "left",
      );
    } finally {
      window.requestAnimationFrame = originalRequestAnimationFrame;
      globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
    }
  });

  it("should observe the resolved breakpoint container and update observation when it changes", async function () {
    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 = [];
    const flushFrames = async () => {
      while (scheduledCallbacks.length > 0) {
        scheduledCallbacks.shift()();
        await new Promise((resolve) => setTimeout(resolve, 0));
      }
    };

    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 = `
        <div id="observed-reference-wrapper">
          <monster-control-bar
            id="observed-reference-bar"
            data-monster-option-layout-stacked-breakpoint="480px"
            data-monster-option-layout-stacked-breakpoint-container="#reference-a"
          >
            <button id="observed-reference-button">Run</button>
          </monster-control-bar>
        </div>
        <div id="reference-a"></div>
        <div id="reference-b"></div>
      `;

      const wrapper = document.getElementById("observed-reference-wrapper");
      const referenceA = document.getElementById("reference-a");
      const referenceB = document.getElementById("reference-b");
      const button = document.getElementById("observed-reference-button");
      const bar = document.getElementById("observed-reference-bar");

      wrapper.style.boxSizing = "border-box";
      referenceA.style.boxSizing = "border-box";
      referenceB.style.boxSizing = "border-box";
      Object.defineProperty(wrapper, "clientWidth", {
        configurable: true,
        value: 459,
      });
      Object.defineProperty(referenceA, "clientWidth", {
        configurable: true,
        value: 640,
      });
      Object.defineProperty(referenceB, "clientWidth", {
        configurable: true,
        value: 350,
      });
      Object.defineProperty(button, "offsetWidth", {
        configurable: true,
        value: 40,
      });
      Object.defineProperty(button, "offsetHeight", {
        configurable: true,
        value: 30,
      });
      button.getBoundingClientRect = () => ({
        width: 40,
        height: 30,
        top: 0,
        right: 40,
        bottom: 30,
        left: 0,
        x: 0,
        y: 0,
        toJSON: () => {},
      });

      await flushFrames();
      await new Promise((resolve) => setTimeout(resolve, 0));
      await new Promise((resolve) => setTimeout(resolve, 0));

      const observer = TrackingResizeObserver.instances[0];
      expect(observer.elements).to.include(referenceA);

      bar.setOption("layout.stackedBreakpointContainer", "#reference-b");
      await flushFrames();
      await new Promise((resolve) => setTimeout(resolve, 0));
      await new Promise((resolve) => setTimeout(resolve, 0));

      expect(observer.elements).to.not.include(referenceA);
      expect(observer.elements).to.include(referenceB);
    } finally {
      window.ResizeObserver = OriginalResizeObserver;
      globalThis.ResizeObserver = originalGlobalResizeObserver;
      window.requestAnimationFrame = originalRequestAnimationFrame;
      globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
    }
  });
});
