import { describe, test, expect, vi, afterEach } from 'vitest';
import React from 'react';
import { createRoot, Root } from 'react-dom/client';
import { act } from 'react-dom/test-utils';
import { Modal } from './Modal';

/* ---------- DOM test harness (no @testing-library/react in this repo, see
   src/ui/AssetPicker.test.tsx for the same pattern: react-dom/client +
   react-dom/test-utils `act`, both transitive deps of react-dom already). ---------- */
let container: HTMLDivElement;
let root: Root;

function render(ui: React.ReactElement) {
  container = document.createElement('div');
  document.body.appendChild(container);
  act(() => {
    root = createRoot(container);
    root.render(ui);
  });
}

function unmount() {
  act(() => { root.unmount(); });
  container.remove();
}

function pressEscape() {
  act(() => {
    window.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
  });
}

function click(el: Element | null) {
  if (!el) throw new Error('element not found');
  act(() => { (el as HTMLElement).dispatchEvent(new MouseEvent('click', { bubbles: true })); });
}

afterEach(() => {
  if (container) unmount();
  document.body.style.overflow = '';
});

describe('Modal', () => {
  test('renders children when open', () => {
    render(<Modal open onClose={vi.fn()}><div data-testid="body">hello</div></Modal>);
    expect(container.querySelector('[data-testid="body"]')?.textContent).toBe('hello');
  });

  test('renders nothing when closed', () => {
    render(<Modal open={false} onClose={vi.fn()}><div data-testid="body">hello</div></Modal>);
    expect(container.querySelector('[data-testid="body"]')).toBeNull();
  });

  test('Escape calls onClose by default', () => {
    const onClose = vi.fn();
    render(<Modal open onClose={onClose}><div>body</div></Modal>);
    pressEscape();
    expect(onClose).toHaveBeenCalledTimes(1);
  });

  test('Escape does not call onClose when closeOnEscape is false', () => {
    const onClose = vi.fn();
    render(<Modal open onClose={onClose} closeOnEscape={false}><div>body</div></Modal>);
    pressEscape();
    expect(onClose).not.toHaveBeenCalled();
  });

  test('clicking the backdrop calls onClose by default', () => {
    const onClose = vi.fn();
    render(<Modal open onClose={onClose}><div data-testid="body">body</div></Modal>);
    // The backdrop is the outermost rendered element.
    click(container.firstElementChild);
    expect(onClose).toHaveBeenCalledTimes(1);
  });

  test('clicking inside the content does not call onClose', () => {
    const onClose = vi.fn();
    render(<Modal open onClose={onClose}><div data-testid="body">body</div></Modal>);
    click(container.querySelector('[data-testid="body"]'));
    expect(onClose).not.toHaveBeenCalled();
  });

  test('clicking the backdrop does not call onClose when closeOnBackdropClick is false', () => {
    const onClose = vi.fn();
    render(<Modal open onClose={onClose} closeOnBackdropClick={false}><div>body</div></Modal>);
    click(container.firstElementChild);
    expect(onClose).not.toHaveBeenCalled();
  });

  test('locks body scroll while open and restores it on close', () => {
    render(<Modal open onClose={vi.fn()}><div>body</div></Modal>);
    expect(document.body.style.overflow).toBe('hidden');
    act(() => { root.render(<Modal open={false} onClose={vi.fn()}><div>body</div></Modal>); });
    expect(document.body.style.overflow).toBe('');
  });
});
