import { afterEach, describe, expect, it, vi } from 'vitest';
import { createRef } from 'react';
import { renderHook } from '@testing-library/react';
import { useOnClickOutside } from '@/hooks/useOnClickOutside';

function mount(): { ref: { current: HTMLDivElement }; inside: HTMLElement; outside: HTMLElement } {
  const container = document.createElement('div');
  const inside = document.createElement('button');
  container.appendChild(inside);
  const outside = document.createElement('div');
  document.body.append(container, outside);
  return { ref: { current: container }, inside, outside };
}

afterEach(() => {
  document.body.innerHTML = '';
});

describe('useOnClickOutside', () => {
  it('calls the handler on a pointer press outside the element', () => {
    const { ref, outside } = mount();
    const handler = vi.fn();
    renderHook(() => useOnClickOutside(ref, handler, true));

    outside.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
    expect(handler).toHaveBeenCalledTimes(1);
  });

  it('ignores presses inside the element', () => {
    const { ref, inside } = mount();
    const handler = vi.fn();
    renderHook(() => useOnClickOutside(ref, handler, true));

    inside.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
    expect(handler).not.toHaveBeenCalled();
  });

  it('does nothing when disabled', () => {
    const { ref, outside } = mount();
    const handler = vi.fn();
    renderHook(() => useOnClickOutside(ref, handler, false));

    outside.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
    expect(handler).not.toHaveBeenCalled();
  });

  it('is safe when the ref is null', () => {
    const ref = createRef<HTMLDivElement>();
    const handler = vi.fn();
    renderHook(() => useOnClickOutside(ref, handler, true));

    // When ref.current is null, the hook returns early without calling handler
    document.body.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
    expect(handler).not.toHaveBeenCalled();
  });
});
