import React from 'react';
import { config } from '@grafana/runtime';
import { renderHook } from '@testing-library/react-hooks';
import { css } from 'emotion';
import { mount } from 'enzyme';
import { memoizedStyleCreators, mockThemeContext, useStyles } from './ThemeContext';

describe('useStyles', () => {
  it('memoizes the passed in function correctly', () => {
    const stylesCreator = () => ({});
    const { rerender, result } = renderHook(() => useStyles(stylesCreator));
    const storedReference = result.current;

    rerender();
    expect(storedReference).toBe(result.current);
  });

  it('does not memoize if the passed in function changes every time', () => {
    const { rerender, result } = renderHook(() => useStyles(() => ({})));
    const storedReference = result.current;
    rerender();
    expect(storedReference).not.toBe(result.current);
  });

  it('updates the memoized function when the theme changes', () => {
    const stylesCreator = () => ({});
    const { rerender, result } = renderHook(() => useStyles(stylesCreator));
    const storedReference = result.current;

    const restoreThemeContext = mockThemeContext({});
    rerender();
    expect(storedReference).not.toBe(result.current);
    restoreThemeContext();
  });

  it('cleans up memoized functions whenever a new one comes along or the component unmounts', () => {
    const styleCreators: Function[] = [];
    const { rerender, unmount } = renderHook(() => {
      const styleCreator = () => ({});
      styleCreators.push(styleCreator);
      return useStyles(styleCreator);
    });

    expect(typeof memoizedStyleCreators.get(styleCreators[0])).toBe('function');
    rerender();
    expect(memoizedStyleCreators.get(styleCreators[0])).toBeUndefined();
    expect(typeof memoizedStyleCreators.get(styleCreators[1])).toBe('function');
    unmount();
    expect(memoizedStyleCreators.get(styleCreators[0])).toBeUndefined();
    expect(memoizedStyleCreators.get(styleCreators[1])).toBeUndefined();
  });

  it('passes in theme and returns style object', (done) => {
    const Dummy: React.FC = function () {
      const styles = useStyles((theme) => {
        expect(theme).toEqual(config.theme);

        return {
          someStyle: css`
            color: ${theme.palette.critical};
          `,
        };
      });

      expect(typeof styles.someStyle).toBe('string');
      done();

      return <div>dummy</div>;
    };

    mount(<Dummy />);
  });
});
