import { renderHook } from '@testing-library/react';
import useTapNavigation from '../useTapNavigation';

describe('useTapNavigation', () => {
  let containerRef: { current: HTMLDivElement | null };
  let onNext: jest.Mock;
  let onPrevious: jest.Mock;

  beforeEach(() => {
    // jsdom does not implement document.elementFromPoint at all, so jest.spyOn
    // won't work. Define it directly, returning null by default
    // (means "no interactive element at the tap point", navigation proceeds normally).
    Object.defineProperty(document, 'elementFromPoint', {
      writable: true,
      configurable: true,
      value: jest.fn().mockReturnValue(null),
    });

    // Create a mock container element with dimensions
    containerRef = { current: document.createElement('div') };

    // Mock getBoundingClientRect to return consistent dimensions
    containerRef.current!.getBoundingClientRect = jest.fn().mockReturnValue({
      width: 1000,
      height: 500,
      top: 0,
      left: 0,
      right: 1000,
      bottom: 500,
      x: 0,
      y: 0,
      toJSON: jest.fn(),
    });

    // Mock event listeners
    containerRef.current!.addEventListener = jest.fn();
    containerRef.current!.removeEventListener = jest.fn();

    // Mock callback functions
    onNext = jest.fn();
    onPrevious = jest.fn();
  });

  afterEach(() => {
    jest.restoreAllMocks();
  });

  test('calls onPrevious when tapping on the left side', () => {
    renderHook(() =>
      useTapNavigation({
        containerRef,
        onNext,
        onPrevious,
      }),
    );

    // Get the click handler
    const clickHandler = (containerRef.current!.addEventListener as jest.Mock).mock.calls.find(
      (call) => call[0] === 'click',
    )[1];

    // Simulate a click on the left side (less than 40% of width)
    const mockClickEvent = {
      clientX: 350, // 35% of container width
      clientY: 250, // Middle of container height
      target: document.createElement('div'),
    };

    clickHandler(mockClickEvent);

    // Check if onPrevious was called
    expect(onPrevious).toHaveBeenCalledTimes(1);
    expect(onNext).not.toHaveBeenCalled();
  });

  test('calls onNext when tapping on the right side', () => {
    renderHook(() =>
      useTapNavigation({
        containerRef,
        onNext,
        onPrevious,
      }),
    );

    // Get the click handler
    const clickHandler = (containerRef.current!.addEventListener as jest.Mock).mock.calls.find(
      (call) => call[0] === 'click',
    )[1];

    // Simulate a click on the right side (more than 40% of width)
    const mockClickEvent = {
      clientX: 600, // 60% of container width
      clientY: 250, // Middle of container height
      target: document.createElement('div'),
    };

    clickHandler(mockClickEvent);

    // Check if onNext was called
    expect(onNext).toHaveBeenCalledTimes(1);
    expect(onPrevious).not.toHaveBeenCalled();
  });

  test('ignores clicks on play button', () => {
    renderHook(() =>
      useTapNavigation({
        containerRef,
        onNext,
        onPrevious,
      }),
    );

    // Get the click handler
    const clickHandler = (containerRef.current!.addEventListener as jest.Mock).mock.calls.find(
      (call) => call[0] === 'click',
    )[1];

    // Make elementFromPoint return a <button> so the hook's interactive-element
    // guard fires and navigation is suppressed.
    const playButton = document.createElement('button');
    (document.elementFromPoint as jest.Mock).mockReturnValue(playButton);

    const mockClickEvent = {
      clientX: 500,
      clientY: 250,
    };

    clickHandler(mockClickEvent);

    // Check that neither callback was called
    expect(onNext).not.toHaveBeenCalled();
    expect(onPrevious).not.toHaveBeenCalled();
  });

  test('does not set up listeners when disabled', () => {
    renderHook(() =>
      useTapNavigation({
        containerRef,
        onNext,
        onPrevious,
        disabled: true,
      }),
    );

    // Check that no event listeners were added
    expect(containerRef.current!.addEventListener).not.toHaveBeenCalled();
  });
});
