import { renderHook } from '@testing-library/react-native';
import React from 'react';
import { useDragShift } from '../../hooks/drag/useDragShift';
import { DragStateProvider } from '../../contexts/DragStateContext';

describe('useDragShift', () => {
  const mockRef = { current: null } as any;

  const createWrapper = () => {
    const Wrapper = ({ children }: { children: React.ReactNode }) => (
      <DragStateProvider>{children}</DragStateProvider>
    );
    return Wrapper;
  };

  it('returns a shiftY SharedValue', async () => {
    const { result } = await renderHook(
      () => useDragShift({ itemId: 'item-1', index: 0, containerRef: mockRef }),
      { wrapper: createWrapper() },
    );

    expect(result.current.shiftY).toBeDefined();
    expect(result.current.shiftY.value).toBe(0);
  });

  it('initializes shiftY to 0', async () => {
    const { result } = await renderHook(
      () => useDragShift({ itemId: 'item-1', index: 0, containerRef: mockRef }),
      { wrapper: createWrapper() },
    );

    expect(result.current.shiftY.value).toBe(0);
  });

  it('returns 0 shift when not dragging', async () => {
    const { result } = await renderHook(
      () => useDragShift({ itemId: 'item-1', index: 1, containerRef: mockRef }),
      { wrapper: createWrapper() },
    );

    // When nothing is being dragged, shiftY should remain 0
    expect(result.current.shiftY.value).toBe(0);
  });

  it('returns 0 shift for the dragged item itself', async () => {
    const { result } = await renderHook(
      () => useDragShift({ itemId: 'dragged-item', index: 2, containerRef: mockRef }),
      { wrapper: createWrapper() },
    );

    // Even if this item is being dragged, it shouldn't shift itself
    expect(result.current.shiftY.value).toBe(0);
  });

  it('uses item index and id from config', async () => {
    const { result } = await renderHook(
      () => useDragShift({ itemId: 'test-item', index: 5, containerRef: mockRef }),
      { wrapper: createWrapper() },
    );

    // Hook should use the provided config values
    expect(result.current.shiftY).toBeDefined();
  });

  it('handles different item indices', async () => {
    // Test with a few different indices sequentially to avoid overlapping act() calls
    for (const index of [0, 2, 4]) {
      const { result } = await renderHook(
        () => useDragShift({ itemId: `item-${index}`, index, containerRef: mockRef }),
        { wrapper: createWrapper() },
      );

      expect(result.current.shiftY).toBeDefined();
      expect(result.current.shiftY.value).toBe(0);
    }
  });

  it('re-renders correctly when config changes', async () => {
    const { result, rerender } = await renderHook(
      ({ itemId, index }) => useDragShift({ itemId, index, containerRef: mockRef }),
      {
        wrapper: createWrapper(),
        initialProps: { itemId: 'item-1', index: 0 },
      },
    );

    // The result.current should be available after async renderHook
    expect(result.current).not.toBeNull();
    expect(result.current.shiftY.value).toBe(0);

    await rerender({ itemId: 'item-2', index: 1 });

    expect(result.current.shiftY).toBeDefined();
  });
});
