import { cleanup, fireEvent, render } from '@testing-library/react';
import { afterEach, describe, expect, it } from 'vitest';
import type { MutableRefObject } from 'react';

import { useRetainedScrollTop } from './useRetainedScrollTop';

function ScrollPane({
  restoreKey,
  savedScrollTopRef,
  suspendSave,
}: {
  restoreKey: string;
  savedScrollTopRef: MutableRefObject<number>;
  suspendSave: boolean;
}) {
  const { scrollRef, onScroll } = useRetainedScrollTop<HTMLDivElement>({
    restoreKey,
    scrollTopRef: savedScrollTopRef,
    suspendSave,
  });

  return (
    <div ref={scrollRef} onScroll={onScroll} data-testid="pane">
      <div style={{ height: 2000 }} />
    </div>
  );
}

describe('useRetainedScrollTop', () => {
  afterEach(() => {
    cleanup();
  });

  it('keeps the saved scroll offset while replacement content is loading', () => {
    const savedScrollTopRef = { current: 0 };
    const view = render(
      <ScrollPane restoreKey="area:a" savedScrollTopRef={savedScrollTopRef} suspendSave={false} />
    );
    const pane = view.getByTestId('pane');

    pane.scrollTop = 360;
    fireEvent.scroll(pane);
    expect(savedScrollTopRef.current).toBe(360);

    view.rerender(
      <ScrollPane restoreKey="area:b" savedScrollTopRef={savedScrollTopRef} suspendSave />
    );

    pane.scrollTop = 0;
    fireEvent.scroll(pane);
    expect(savedScrollTopRef.current).toBe(360);

    view.rerender(
      <ScrollPane restoreKey="area:b" savedScrollTopRef={savedScrollTopRef} suspendSave={false} />
    );

    expect(pane.scrollTop).toBe(360);
  });

  it('restores the saved offset when a pane remounts', () => {
    const savedScrollTopRef = { current: 220 };
    const view = render(
      <ScrollPane restoreKey="area:a" savedScrollTopRef={savedScrollTopRef} suspendSave={false} />
    );

    expect(view.getByTestId('pane').scrollTop).toBe(220);
  });
});
