import { useRef } from 'react';
import { act, cleanup, fireEvent } from '@testing-library/react';
import { render } from '../../../utils/theme-render-wrapper';

import { useResizeObserverEffect, useToggleOnFocus, useWindowEventListener } from '.';

beforeEach(() => jest.useFakeTimers());

afterEach(() => {
  jest.useRealTimers();
  cleanup();
});

const text = 'Lorem ipsum dolor sit amet';

const ToggleOnFocusTestComponent = ({ initialState }: { initialState?: boolean }) => {
  const { currentState, eventHandlers } = useToggleOnFocus(initialState);

  return (
    <button onFocus={e => eventHandlers.onFocus()} onBlur={e => eventHandlers.onBlur()}>
      {currentState ? 'focused' : 'blurred'}
    </button>
  );
};

const ResizeObserverEffectTestComponent = ({ callback }: { callback: () => void }) => {
  const ref = useRef<HTMLDivElement>(null);
  useResizeObserverEffect(callback, ref?.current);

  return <div ref={ref}>{text}</div>;
};

const WindowEventListenerTestComponent = ({
  eventListener
}: {
  eventListener: (event?: Event) => void;
}) => {
  useWindowEventListener(['click'], eventListener);

  return <button>{text}</button>;
};

describe('Check "utils/common/hooks"', () => {
  describe('useToggleOnFocus', () => {
    it(`check default`, () => {
      const { container } = render(<ToggleOnFocusTestComponent />);
      expect(container.textContent).toBe('blurred');
    });

    it(`check focused`, () => {
      const setTimeoutSpy = jest.spyOn(global, 'setTimeout');

      act(() => {
        const { queryByRole } = render(<ToggleOnFocusTestComponent initialState={false} />);
        const buttonEl = queryByRole('button');
        expect(buttonEl?.textContent).toBe('blurred');
        buttonEl && fireEvent.focus(buttonEl);

        jest.runAllTimers();
        expect(buttonEl?.textContent).toBe('focused');
      });

      expect(setTimeoutSpy).toHaveBeenCalledTimes(1);
      setTimeoutSpy.mockClear();
    });

    it(`check blurred`, () => {
      const setTimeoutSpy = jest.spyOn(global, 'setTimeout');

      act(() => {
        const { queryByRole } = render(<ToggleOnFocusTestComponent initialState={true} />);
        const buttonEl = queryByRole('button');
        expect(buttonEl?.textContent).toBe('focused');

        buttonEl && fireEvent.blur(buttonEl);
        jest.runAllTimers();
        expect(buttonEl?.textContent).toBe('blurred');
      });

      expect(setTimeoutSpy).toHaveBeenCalledTimes(2);
      setTimeoutSpy.mockClear();
    });
  });

  describe('useResizeObserverEffect', () => {
    it(`check with ResizeObserver mock`, () => {
      const callback = jest.fn();
      render(<ResizeObserverEffectTestComponent callback={callback} />);
      expect(callback).toHaveBeenCalledTimes(1);
    });
  });

  describe('useWindowEventListener', () => {
    it(`check with click event`, () => {
      const eventListener = jest.fn();
      const { container } = render(
        <WindowEventListenerTestComponent eventListener={eventListener} />
      );
      container.click();
      expect(eventListener).toHaveBeenCalledTimes(1);
    });
  });
});
