import { renderHook, act } from '@testing-library/react';
import { useCarouselMinHeight } from '../useCarouselMinHeight';
import {RefObject} from 'react';

type ResizeObserverCallback = (entries: ResizeObserverEntry[]) => void;

class ResizeObserverMock {
  callback: ResizeObserverCallback;
  observe: ResizeObserver['observe'];
  unobserve: ResizeObserver['unobserve'];
  disconnect: ResizeObserver['disconnect'];

  constructor(callback: ResizeObserverCallback) {
    this.callback = callback;
    this.observe = jest.fn();
    this.unobserve = jest.fn();
    this.disconnect = jest.fn();
  }
}

const createEntry = (target: Element, height: number): ResizeObserverEntry =>
  ({
    target,
    contentRect: { height } as DOMRectReadOnly,
    borderBoxSize: [] as unknown as ReadonlyArray<ResizeObserverSize>,
    contentBoxSize: [] as unknown as ReadonlyArray<ResizeObserverSize>,
    devicePixelContentBoxSize: [] as unknown as ReadonlyArray<ResizeObserverSize>,
  } as ResizeObserverEntry);

describe('useCarouselMinHeight', () => {
  let observerCallback: ResizeObserverCallback | null = null;

  beforeAll(() => {
    global.ResizeObserver = jest.fn((cb: ResizeObserverCallback) => {
      observerCallback = cb;
      return new ResizeObserverMock(cb);
    }) as unknown as typeof ResizeObserver;
  });

  beforeEach(() => {
    observerCallback = null;
    jest.clearAllMocks();
  });

  const createRef = () => ({
    current: document.createElement('div'),
  });

  it('returns base min height when disabled', () => {
    const ref = createRef();

    const { result, rerender } = renderHook(
      ({ enabled }) =>
        useCarouselMinHeight(ref as RefObject<HTMLElement>, 120, enabled, 'key'),
      {
        initialProps: { enabled: false },
      }
    );

    expect(result.current).toBe(120);

    rerender({ enabled: true });
    expect(result.current).toBe(120);

    rerender({ enabled: false });
    expect(result.current).toBe(120);
  });

  it('tracks tallest observed height while enabled', () => {
    const ref = createRef();

    const { result } = renderHook(() =>
      useCarouselMinHeight(ref as RefObject<HTMLElement>, 120, true, 'key')
    );

    expect(result.current).toBe(120);

    act(() => {
      observerCallback?.([createEntry(ref.current as Element, 140)]);
    });

    expect(result.current).toBe(140);

    act(() => {
      observerCallback?.([createEntry(ref.current as Element, 130)]);
    });

    expect(result.current).toBe(140);
  });

  it('resets when disabled or observe key changes', () => {
    const ref = createRef();

    const { result, rerender } = renderHook(
      ({ enabled, key }) =>
        useCarouselMinHeight(ref as RefObject<HTMLElement>, 120, enabled, key),
      {
        initialProps: { enabled: true, key: 'first' },
      }
    );

    act(() => {
      observerCallback?.([createEntry(ref.current as Element, 200)]);
    });

    expect(result.current).toBe(200);

    rerender({ enabled: false, key: 'first' });
    expect(result.current).toBe(120);

    rerender({ enabled: true, key: 'second' });
    expect(result.current).toBe(120);

    act(() => {
      observerCallback?.([createEntry(ref.current as Element, 150)]);
    });

    expect(result.current).toBe(150);
  });
});
