// @vitest-environment jsdom
/**
 * Tests for ScrollUpButton per TZ §4.1.14 Table 22:
 * - Desktop/tablet: scroll-up button appears when breadcrumbs + title + switcher + tabs
 *   scroll out of view (approximated by a scroll threshold).
 * - Mobile: scroll-up button appears when list scrolls past screen bottom.
 *
 * NOTE: Visual regression (sticky CSS position) must be verified separately in
 * a browser environment. jsdom does not compute CSS layout.
 */
import { describe, it, expect, vi, afterEach } from "vitest";
import { render, screen, act } from "@testing-library/react";
import { ScrollUpButton } from "./ScrollUpButton.js";

vi.mock("@/i18n/provider.js", () => ({
  useTranslation: () => ({ t: (k: string) => k }),
}));

vi.mock("./ScrollUpButton.scss", () => ({}));

// Helper to fire a scroll event at a given scrollY
function fireScrollAt(scrollY: number) {
  Object.defineProperty(window, "scrollY", { value: scrollY, writable: true, configurable: true });
  window.dispatchEvent(new Event("scroll"));
}

afterEach(() => {
  Object.defineProperty(window, "scrollY", { value: 0, writable: true, configurable: true });
});

describe("4.1.14-R-ScrollUp: ScrollUpButton visibility per TZ Table 22", () => {
  it("button is hidden on initial render (scrollY = 0)", () => {
    Object.defineProperty(window, "scrollY", { value: 0, writable: true, configurable: true });
    render(<ScrollUpButton />);
    expect(screen.queryByTestId("scroll-up-button")).toBeNull();
  });

  it("button is hidden when scroll is below threshold (scrollY = 100)", () => {
    Object.defineProperty(window, "scrollY", { value: 0, writable: true, configurable: true });
    render(<ScrollUpButton />);
    act(() => { fireScrollAt(100); });
    expect(screen.queryByTestId("scroll-up-button")).toBeNull();
  });

  it("button is hidden at exactly the threshold boundary (scrollY = 300)", () => {
    Object.defineProperty(window, "scrollY", { value: 0, writable: true, configurable: true });
    render(<ScrollUpButton />);
    act(() => { fireScrollAt(300); });
    // threshold is > 300, so at 300 it should still be hidden
    expect(screen.queryByTestId("scroll-up-button")).toBeNull();
  });

  it("button appears when scrolled past threshold (scrollY = 301)", () => {
    Object.defineProperty(window, "scrollY", { value: 0, writable: true, configurable: true });
    render(<ScrollUpButton />);
    act(() => { fireScrollAt(301); });
    expect(screen.getByTestId("scroll-up-button")).toBeTruthy();
  });

  it("button appears when scrolled well past threshold (scrollY = 800)", () => {
    Object.defineProperty(window, "scrollY", { value: 0, writable: true, configurable: true });
    render(<ScrollUpButton />);
    act(() => { fireScrollAt(800); });
    expect(screen.getByTestId("scroll-up-button")).toBeTruthy();
  });

  it("button disappears after scrolling back up below threshold", () => {
    Object.defineProperty(window, "scrollY", { value: 0, writable: true, configurable: true });
    render(<ScrollUpButton />);
    act(() => { fireScrollAt(800); });
    expect(screen.getByTestId("scroll-up-button")).toBeTruthy();
    act(() => { fireScrollAt(50); });
    expect(screen.queryByTestId("scroll-up-button")).toBeNull();
  });

  it("button has correct aria-label for accessibility", () => {
    Object.defineProperty(window, "scrollY", { value: 0, writable: true, configurable: true });
    render(<ScrollUpButton />);
    act(() => { fireScrollAt(400); });
    const btn = screen.getByTestId("scroll-up-button");
    expect(btn.getAttribute("aria-label")).toBe("SHARED.A11Y-SCROLL-TO-TOP");
  });

  it("button is type=button (not submit) to avoid accidental form submission", () => {
    Object.defineProperty(window, "scrollY", { value: 0, writable: true, configurable: true });
    render(<ScrollUpButton />);
    act(() => { fireScrollAt(400); });
    const btn = screen.getByTestId("scroll-up-button");
    expect(btn.getAttribute("type")).toBe("button");
  });

  it("scroll listener is cleaned up on unmount (no memory leaks)", () => {
    Object.defineProperty(window, "scrollY", { value: 0, writable: true, configurable: true });
    const removeEventListenerSpy = vi.spyOn(window, "removeEventListener");
    const { unmount } = render(<ScrollUpButton />);
    unmount();
    expect(removeEventListenerSpy).toHaveBeenCalledWith("scroll", expect.any(Function));
    removeEventListenerSpy.mockRestore();
  });
});
