import { act } from "react";
import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";

import { ModalPortal } from "../modal-portal";

describe("ModalPortal", () => {
  let container: HTMLDivElement;
  let root: Root;

  beforeEach(() => {
    (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean })
      .IS_REACT_ACT_ENVIRONMENT = true;
    container = document.createElement("div");
    container.style.transform = "translateX(50%)";
    document.body.appendChild(container);
    document.body.style.overflow = "auto";
    root = createRoot(container);
  });

  afterEach(() => {
    act(() => root.unmount());
    container.remove();
    document.body.style.overflow = "";
  });

  it("portals outside transformed ancestors and exposes dialog semantics", () => {
    const onClose = vi.fn();

    act(() =>
      root.render(
        <ModalPortal
          open
          onClose={onClose}
          scrimClassName="fixed inset-0"
          panelClassName="payment-panel"
          scrimOpacity={0.5}
          role="alertdialog"
          ariaLabelledBy="payment-title"
          ariaDescribedBy="payment-description"
        >
          <h2 id="payment-title">Complete payment</h2>
          <p id="payment-description">Choose a payment method.</p>
        </ModalPortal>,
      ),
    );

    const dialog = document.body.querySelector('[role="alertdialog"]');
    expect(dialog).not.toBeNull();
    expect(container.contains(dialog)).toBe(false);
    expect(dialog?.parentElement?.parentElement).toBe(document.body);
    expect(dialog?.getAttribute("aria-labelledby")).toBe("payment-title");
    expect(dialog?.getAttribute("aria-describedby")).toBe(
      "payment-description",
    );
    expect(document.body.style.overflow).toBe("hidden");
  });

  it("restores the previous body overflow after the final modal closes", () => {
    const renderModals = (showFirst: boolean, showSecond: boolean) => (
      <>
        <ModalPortal
          open={showFirst}
          onClose={() => undefined}
          scrimClassName="first-scrim"
          panelClassName="first-panel"
          scrimOpacity={0.4}
        >
          First
        </ModalPortal>
        <ModalPortal
          open={showSecond}
          onClose={() => undefined}
          scrimClassName="second-scrim"
          panelClassName="second-panel"
          scrimOpacity={0.4}
        >
          Second
        </ModalPortal>
      </>
    );

    act(() => root.render(renderModals(true, true)));
    expect(document.body.style.overflow).toBe("hidden");

    act(() => root.render(renderModals(false, true)));
    expect(document.body.style.overflow).toBe("hidden");

    act(() => root.render(renderModals(false, false)));
    expect(document.body.style.overflow).toBe("auto");
  });

  it("keeps persistent payment modals open on scrim click and Escape", () => {
    const onClose = vi.fn();

    act(() =>
      root.render(
        <ModalPortal
          open
          persistent
          onClose={onClose}
          scrimClassName="fixed inset-0"
          panelClassName="payment-panel"
          scrimOpacity={0.5}
        >
          Payment
        </ModalPortal>,
      ),
    );

    const scrim = document.body.querySelector(".fixed.inset-0");
    act(() => scrim?.dispatchEvent(new MouseEvent("click", { bubbles: true })));
    act(() =>
      document.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape" })),
    );

    expect(onClose).not.toHaveBeenCalled();
  });
});
