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

import { ThemeProvider } from './ThemeProvider';
import { DEFAULT_BASE_THEME, DEFAULT_SCREEN_MODE } from './const';
import { useTheme } from './useTheme';

describe('useTheme', () => {
  it('returns default light theme', () => {
    jest.spyOn(console, 'warn').mockImplementation();

    const {
      result: { current },
    } = renderHook(() => useTheme());

    expect(current).toMatchObject({
      theme: DEFAULT_BASE_THEME,
      screenMode: DEFAULT_SCREEN_MODE,
      isModern: true,
      isForestGreenTheme: false,
      isScreenModeDark: false,
      className: 'np-theme-personal',
    });
    expect(current.setTheme).toBeInstanceOf(Function);
    expect(current.setScreenMode).toBeInstanceOf(Function);

    jest.clearAllMocks();
  });

  it('returns personal theme', () => {
    const {
      result: { current },
    } = renderHook(() => useTheme(), {
      wrapper: (props) => <ThemeProvider theme="personal" {...props} />,
    });

    expect(current).toMatchObject({
      theme: 'personal',
      screenMode: DEFAULT_SCREEN_MODE,
      isModern: true,
      isForestGreenTheme: false,
      isScreenModeDark: false,
      className: 'np-theme-personal',
    });
    expect(current.setTheme).toBeInstanceOf(Function);
    expect(current.setScreenMode).toBeInstanceOf(Function);
  });

  it('returns forest-green theme', () => {
    const {
      result: { current },
    } = renderHook(() => useTheme(), {
      wrapper: (props) => <ThemeProvider theme="forest-green" {...props} />,
    });

    expect(current).toMatchObject({
      theme: 'forest-green',
      screenMode: DEFAULT_SCREEN_MODE,
      isModern: true,
      isForestGreenTheme: true,
      isScreenModeDark: false,
      className: 'np-theme-personal np-theme-personal--forest-green',
    });
    expect(current.setTheme).toBeInstanceOf(Function);
    expect(current.setScreenMode).toBeInstanceOf(Function);
  });

  it('returns bright-green theme', () => {
    const {
      result: { current },
    } = renderHook(() => useTheme(), {
      wrapper: (props) => <ThemeProvider theme="bright-green" {...props} />,
    });

    expect(current).toMatchObject({
      theme: 'bright-green',
      screenMode: DEFAULT_SCREEN_MODE,
      isModern: true,
      isForestGreenTheme: false,
      isScreenModeDark: false,
      className: 'np-theme-personal np-theme-personal--bright-green',
    });
    expect(current.setTheme).toBeInstanceOf(Function);
    expect(current.setScreenMode).toBeInstanceOf(Function);
  });

  it('returns default screen mode if used light theme', () => {
    const {
      result: { current },
    } = renderHook(() => useTheme(), {
      wrapper: (props) => <ThemeProvider theme="light" {...props} />,
    });

    expect(current).toMatchObject({
      theme: DEFAULT_BASE_THEME,
      screenMode: DEFAULT_SCREEN_MODE,
      isModern: true,
      isForestGreenTheme: false,
      isScreenModeDark: false,
      className: 'np-theme-personal',
    });
    expect(current.setTheme).toBeInstanceOf(Function);
    expect(current.setScreenMode).toBeInstanceOf(Function);
  });

  it('returns dark screen mode if used light theme + dark screen mode', () => {
    const {
      result: { current },
    } = renderHook(() => useTheme(), {
      wrapper: (props) => <ThemeProvider theme="light" screenMode="dark" {...props} />,
    });

    expect(current).toMatchObject({
      theme: DEFAULT_BASE_THEME,
      screenMode: 'dark',
      isModern: true,
      isForestGreenTheme: false,
      isScreenModeDark: true,
      className: 'np-theme-personal np-theme-personal--dark',
    });
    expect(current.setTheme).toBeInstanceOf(Function);
    expect(current.setScreenMode).toBeInstanceOf(Function);
  });

  it('returns dark screen mode', () => {
    const {
      result: { current },
    } = renderHook(() => useTheme(), {
      wrapper: (props) => <ThemeProvider theme="personal" screenMode="dark" {...props} />,
    });

    expect(current).toMatchObject({
      theme: 'personal',
      screenMode: 'dark',
      isModern: true,
      isForestGreenTheme: false,
      isScreenModeDark: true,
      className: 'np-theme-personal np-theme-personal--dark',
    });
    expect(current.setTheme).toBeInstanceOf(Function);
    expect(current.setScreenMode).toBeInstanceOf(Function);
  });
  it('warns when used outside a theme provider on staging or localhost', () => {
    jest.spyOn(console, 'warn').mockImplementation();

    Object.defineProperty(window, 'location', {
      value: {
        hostname: 'wise.com',
      },
      writable: true,
    });

    const {
      result: { current: productionValue },
    } = renderHook(() => useTheme());

    expect(productionValue).toMatchObject({
      theme: DEFAULT_BASE_THEME,
      screenMode: DEFAULT_SCREEN_MODE,
      isModern: true,
      isForestGreenTheme: false,
      isScreenModeDark: false,
      className: 'np-theme-personal',
    });
    expect(productionValue.setTheme).toBeInstanceOf(Function);
    expect(productionValue.setScreenMode).toBeInstanceOf(Function);

    // eslint-disable-next-line no-console
    expect(console.warn).not.toHaveBeenCalled();

    Object.defineProperty(window, 'location', {
      value: {
        hostname: 'dev-wi.se',
      },
      writable: true,
    });

    const {
      result: { current: stagingValue },
    } = renderHook(() => useTheme());

    expect(stagingValue).toMatchObject({
      theme: DEFAULT_BASE_THEME,
      screenMode: DEFAULT_SCREEN_MODE,
      isModern: true,
      isForestGreenTheme: false,
      isScreenModeDark: false,
      className: 'np-theme-personal',
    });
    expect(stagingValue.setTheme).toBeInstanceOf(Function);
    expect(stagingValue.setScreenMode).toBeInstanceOf(Function);

    // eslint-disable-next-line no-console
    expect(console.warn).toHaveBeenCalledTimes(1);

    Object.defineProperty(window, 'location', {
      value: {
        hostname: 'localhost',
      },
      writable: true,
    });

    const {
      result: { current: localhostValue },
    } = renderHook(() => useTheme());

    expect(localhostValue).toMatchObject({
      theme: DEFAULT_BASE_THEME,
      screenMode: DEFAULT_SCREEN_MODE,
      isModern: true,
      isForestGreenTheme: false,
      isScreenModeDark: false,
      className: 'np-theme-personal',
    });
    expect(localhostValue.setTheme).toBeInstanceOf(Function);
    expect(localhostValue.setScreenMode).toBeInstanceOf(Function);

    // eslint-disable-next-line no-console
    expect(console.warn).toHaveBeenCalledTimes(2);

    Object.defineProperty(window, 'location', {
      value: undefined,
      writable: true,
    });

    const {
      result: { current: noHostnameValue },
    } = renderHook(() => useTheme());

    expect(noHostnameValue).toMatchObject({
      theme: DEFAULT_BASE_THEME,
      screenMode: DEFAULT_SCREEN_MODE,
      isModern: true,
      isForestGreenTheme: false,
      isScreenModeDark: false,
      className: 'np-theme-personal',
    });
    expect(noHostnameValue.setTheme).toBeInstanceOf(Function);
    expect(noHostnameValue.setScreenMode).toBeInstanceOf(Function);

    // eslint-disable-next-line no-console
    expect(console.warn).toHaveBeenCalledTimes(2);

    jest.clearAllMocks();
  });

  it('allows theme changes from child components via setTheme', async () => {
    const { result } = renderHook(() => useTheme(), {
      wrapper: (props) => <ThemeProvider theme="personal" {...props} />,
    });

    expect(result.current.theme).toBe('personal');

    // Change theme using setTheme
    await act(async () => {
      result.current.setTheme('business');
    });

    expect(result.current.theme).toBe('business');
  });

  it('allows screen mode changes from child components via setScreenMode', async () => {
    const { result } = renderHook(() => useTheme(), {
      wrapper: (props) => <ThemeProvider theme="personal" screenMode="light" {...props} />,
    });

    expect(result.current.screenMode).toBe('light');

    // Change screen mode using setScreenMode
    await act(async () => {
      result.current.setScreenMode('dark');
    });

    expect(result.current.screenMode).toBe('dark');
  });
});
