// @vitest-environment jsdom
/**
 * Hook test for useEdgeSwipe — exercises the touch-event handlers (not just the
 * pure evaluateEdgeSwipe, which has its own suite). Verifies start/end gesture
 * tracking, the enabled gate, edge-band gate on touchstart, and onTouchCancel
 * clearing the in-flight gesture so a later end does not fire.
 */
import '../test/dom-setup';
import { describe, it, expect, vi } from 'vitest';
import { renderHook } from '@testing-library/react';
import { useEdgeSwipe } from './useEdgeSwipe';
import type { TouchEvent } from 'react';

// Build a minimal synthetic React TouchEvent with the fields the hook reads.
function touchEvent(
  kind: 'start' | 'end',
  x: number,
  y: number,
): TouchEvent<HTMLElement> {
  const point = { clientX: x, clientY: y } as Touch;
  return {
    touches: kind === 'start' ? [point] : [],
    changedTouches: kind === 'end' ? [point] : [],
  } as unknown as TouchEvent<HTMLElement>;
}

describe('useEdgeSwipe (touch handlers)', () => {
  it('fires onOpen for an edge→right swipe past threshold', () => {
    const onOpen = vi.fn();
    const { result } = renderHook(() => useEdgeSwipe({ onOpen }));
    result.current.onTouchStart(touchEvent('start', 5, 100));
    result.current.onTouchEnd(touchEvent('end', 80, 100));
    expect(onOpen).toHaveBeenCalledTimes(1);
  });

  it('does not fire when the gesture starts outside the edge band', () => {
    const onOpen = vi.fn();
    const { result } = renderHook(() => useEdgeSwipe({ onOpen }));
    // start.current never set because touchstart bails on x >= edgeWidth
    result.current.onTouchStart(touchEvent('start', 200, 100));
    result.current.onTouchEnd(touchEvent('end', 300, 100));
    expect(onOpen).not.toHaveBeenCalled();
  });

  it('does not fire when horizontal travel is below threshold', () => {
    const onOpen = vi.fn();
    const { result } = renderHook(() => useEdgeSwipe({ onOpen }));
    result.current.onTouchStart(touchEvent('start', 5, 100));
    result.current.onTouchEnd(touchEvent('end', 40, 100));
    expect(onOpen).not.toHaveBeenCalled();
  });

  it('respects enabled=false (no tracking, no open)', () => {
    const onOpen = vi.fn();
    const { result } = renderHook(() => useEdgeSwipe({ onOpen, enabled: false }));
    result.current.onTouchStart(touchEvent('start', 5, 100));
    result.current.onTouchEnd(touchEvent('end', 200, 100));
    expect(onOpen).not.toHaveBeenCalled();
  });

  it('onTouchCancel clears the in-flight gesture so a later end is ignored', () => {
    const onOpen = vi.fn();
    const { result } = renderHook(() => useEdgeSwipe({ onOpen }));
    result.current.onTouchStart(touchEvent('start', 5, 100));
    result.current.onTouchCancel();
    result.current.onTouchEnd(touchEvent('end', 200, 100));
    expect(onOpen).not.toHaveBeenCalled();
  });

  it('honors custom thresholds via options', () => {
    const onOpen = vi.fn();
    const { result } = renderHook(() =>
      useEdgeSwipe({ onOpen, edgeWidth: 10, openThreshold: 30 }),
    );
    result.current.onTouchStart(touchEvent('start', 8, 50));
    result.current.onTouchEnd(touchEvent('end', 40, 50)); // dx=32 > 30
    expect(onOpen).toHaveBeenCalledTimes(1);
  });
});
