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

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

  it('does not throw when initialized', async () => {
    const translateY = createMockSharedValue(0);
    const shiftY = createMockSharedValue(0);

    await expect(
      renderHook(
        () =>
          useDropCompensation({
            itemId: 'item-1',
            index: 0,
            translateY: translateY as any,
            shiftY: shiftY as any,
          }),
        { wrapper: createWrapper() },
      ),
    ).resolves.toBeDefined();
  });

  it('handles index unchanged scenario', async () => {
    const translateY = createMockSharedValue(0);
    const shiftY = createMockSharedValue(0);

    const { rerender } = await renderHook(
      ({ index }) =>
        useDropCompensation({
          itemId: 'item-1',
          index,
          translateY: translateY as any,
          shiftY: shiftY as any,
        }),
      {
        wrapper: createWrapper(),
        initialProps: { index: 0 },
      },
    );

    // Rerender with same index
    await rerender({ index: 0 });

    // Should not modify translateY when index doesn't change
    expect(translateY.value).toBe(0);
  });

  it('works with different item IDs', async () => {
    const translateY = createMockSharedValue(0);
    const shiftY = createMockSharedValue(0);

    const { rerender } = await renderHook(
      ({ itemId, index }) =>
        useDropCompensation({
          itemId,
          index,
          translateY: translateY as any,
          shiftY: shiftY as any,
        }),
      {
        wrapper: createWrapper(),
        initialProps: { itemId: 'item-1', index: 0 },
      },
    );

    // Rerender with different itemId (view recycling)
    await rerender({ itemId: 'item-2', index: 0 });

    expect(translateY.value).toBe(0);
  });

  it('tracks index changes via shared value', async () => {
    const translateY = createMockSharedValue(0);
    const shiftY = createMockSharedValue(0);

    const { rerender } = await renderHook(
      ({ index }) =>
        useDropCompensation({
          itemId: 'item-1',
          index,
          translateY: translateY as any,
          shiftY: shiftY as any,
        }),
      {
        wrapper: createWrapper(),
        initialProps: { index: 0 },
      },
    );

    // Rerender with new index
    await rerender({ index: 1 });

    // Hook should track the index change
  });

  it('handles multiple items with different indices', async () => {
    // Iterate sequentially to avoid overlapping act() calls
    for (const index of [0, 1, 2, 3, 4]) {
      const translateY = createMockSharedValue(0);
      const shiftY = createMockSharedValue(0);

      // useDropCompensation returns void - just verify it doesn't throw
      await expect(
        renderHook(
          () =>
            useDropCompensation({
              itemId: `item-${index}`,
              index,
              translateY: translateY as any,
              shiftY: shiftY as any,
            }),
          { wrapper: createWrapper() },
        ),
      ).resolves.toBeDefined();
    }
  });

  it('unmounts cleanly', async () => {
    const translateY = createMockSharedValue(0);
    const shiftY = createMockSharedValue(0);

    const { unmount } = await renderHook(
      () =>
        useDropCompensation({
          itemId: 'item-1',
          index: 0,
          translateY: translateY as any,
          shiftY: shiftY as any,
        }),
      { wrapper: createWrapper() },
    );

    expect(() => unmount()).not.toThrow();
  });

  it('works with non-zero initial shiftY', async () => {
    const translateY = createMockSharedValue(0);
    const shiftY = createMockSharedValue(80);

    await renderHook(
      () =>
        useDropCompensation({
          itemId: 'item-1',
          index: 0,
          translateY: translateY as any,
          shiftY: shiftY as any,
        }),
      { wrapper: createWrapper() },
    );

    // Hook should handle non-zero shiftY
    expect(shiftY.value).toBe(80);
  });

  it('works with non-zero initial translateY', async () => {
    const translateY = createMockSharedValue(100);
    const shiftY = createMockSharedValue(0);

    await renderHook(
      () =>
        useDropCompensation({
          itemId: 'item-1',
          index: 0,
          translateY: translateY as any,
          shiftY: shiftY as any,
        }),
      { wrapper: createWrapper() },
    );

    // Hook should handle non-zero translateY
    expect(translateY.value).toBe(100);
  });
});
