import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
import { act } from 'react';
import { createRoot, type Root } from 'react-dom/client';
import { usePanesStore } from '../stores/PanesStore';
import { PaneToggleStrip } from './PaneToggleStrip';

vi.mock('../modals/ModalCoordinator', () => ({ openModal: vi.fn() }));
import { openModal } from '../modals/ModalCoordinator';

(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;

let container: HTMLDivElement;
let root: Root;

const toggleButtons = () =>
  Array.from(container.querySelectorAll<HTMLButtonElement>('button[aria-pressed]'));
const datasetsButton = () =>
  container.querySelector<HTMLButtonElement>('button[aria-label="Datasets"]')!;

beforeEach(() => {
  usePanesStore.getState().hydrate({}, {});
  container = document.createElement('div');
  document.body.appendChild(container);
  root = createRoot(container);
  act(() => root.render(<PaneToggleStrip />));
});

afterEach(() => {
  act(() => root.unmount());
  container.remove();
  vi.clearAllMocks();
});

describe('PaneToggleStrip', () => {
  test('renders an APG toolbar: three pane toggles + a Datasets command button', () => {
    expect(container.querySelector('[role="toolbar"][aria-orientation="vertical"]')).not.toBeNull();
    expect(toggleButtons()).toHaveLength(3);
    // The Datasets control is a command button, not a toggle (no aria-pressed).
    expect(datasetsButton().hasAttribute('aria-pressed')).toBe(false);
  });

  test('aria-pressed mirrors pane visibility and flips on click', () => {
    const [library] = toggleButtons();
    expect(library.getAttribute('aria-pressed')).toBe('true');

    act(() => library.click());

    expect(usePanesStore.getState().libraryVisible).toBe(false);
    expect(library.getAttribute('aria-pressed')).toBe('false');
  });

  test('the accessible name is stable across the pressed/not-pressed flip (APG)', () => {
    const [library] = toggleButtons();
    expect(library.getAttribute('aria-label')).toBe('Library pane');
    act(() => library.click());
    expect(library.getAttribute('aria-label')).toBe('Library pane');
  });

  test('aria-controls points at the pane only while it is shown (no dangling IDREF)', () => {
    // App unmounts a hidden pane's <section>, so emitting aria-controls then would
    // leave the IDREF pointing at nothing. It must appear only when pressed/shown.
    const [library] = toggleButtons();
    expect(library.hasAttribute('aria-controls')).toBe(true);

    act(() => library.click()); // hide the pane

    expect(library.getAttribute('aria-pressed')).toBe('false');
    expect(library.hasAttribute('aria-controls')).toBe(false);
  });

  test('roving tabindex: exactly one control is in the tab order at a time', () => {
    const all = [...toggleButtons(), datasetsButton()];
    expect(all.filter((b) => b.tabIndex === 0)).toHaveLength(1);
    expect(all[0].tabIndex).toBe(0); // first control by default
  });

  test('ArrowDown moves the roving tab stop to the next control', () => {
    const all = [...toggleButtons(), datasetsButton()];
    act(() => {
      all[0].dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));
    });
    expect(all[0].tabIndex).toBe(-1);
    expect(all[1].tabIndex).toBe(0);
  });

  test('End jumps to the last control (Datasets); Home returns to the first', () => {
    const all = [...toggleButtons(), datasetsButton()];
    act(() => {
      all[0].dispatchEvent(new KeyboardEvent('keydown', { key: 'End', bubbles: true }));
    });
    expect(datasetsButton().tabIndex).toBe(0);

    act(() => {
      datasetsButton().dispatchEvent(new KeyboardEvent('keydown', { key: 'Home', bubbles: true }));
    });
    expect(all[0].tabIndex).toBe(0);
  });

  test('ArrowUp from the first control wraps to the last', () => {
    const all = [...toggleButtons(), datasetsButton()];
    act(() => {
      all[0].dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp', bubbles: true }));
    });
    expect(datasetsButton().tabIndex).toBe(0);
  });

  test('the Datasets button opens the Datasets manager', () => {
    act(() => datasetsButton().click());
    expect(openModal).toHaveBeenCalledWith('datasets');
  });
});
