import { fireEvent, render, screen, waitFor } from '@testing-library/react';

import { ThemeProvider, ThemeProviderProps } from './ThemeProvider';
import { useState } from 'react';

describe('ThemeProvider', () => {
  it('tests local theme provider (isNotRootProvider) has not affect on root theme (on html element)', () => {
    render(
      <ThemeProvider theme="personal" screenMode="dark" isNotRootProvider>
        <div>local-theme-provider</div>
      </ThemeProvider>,
    );

    // global theme isn't affected (in this case isn't set)
    expect(document.documentElement).not.toHaveClass(
      'np-theme-personal',
      'np-theme-personal--dark',
    );

    // only local theme being set
    // eslint-disable-next-line testing-library/no-node-access
    expect(screen.getByText('local-theme-provider').parentElement).toHaveClass(
      'np-theme-personal np-theme-personal--dark',
    );
  });

  it('tests root provider set root theme (on html element) and it is not affected by nested provider(s)', () => {
    render(
      <ThemeProvider theme="personal" screenMode="dark">
        <div>root-dark-theme</div>
        <ThemeProvider theme="forest-green">
          <div>nested-forest-green</div>
        </ThemeProvider>
        <ThemeProvider theme="personal" screenMode="light">
          <div>nested-personal</div>
        </ThemeProvider>
      </ThemeProvider>,
    );

    // root provider set dark theme and it wasn't changed by two nested providers
    expect(document.documentElement).toHaveClass('np-theme-personal np-theme-personal--dark');

    // eslint-disable-next-line testing-library/no-node-access
    expect(screen.getByText('root-dark-theme').parentElement).toHaveClass(
      'np-theme-personal np-theme-personal--dark',
    );
    // eslint-disable-next-line testing-library/no-node-access
    expect(screen.getByText('nested-forest-green').parentElement).toHaveClass(
      'np-theme-personal np-theme-personal--forest-green',
    );
    // eslint-disable-next-line testing-library/no-node-access
    expect(screen.getByText('nested-personal').parentElement).toHaveClass('np-theme-personal');
  });

  it('tests deprecated light theme normalization', () => {
    render(
      <ThemeProvider theme="light">
        <div>light</div>
        <ThemeProvider theme="personal">
          <div>personal</div>
        </ThemeProvider>
        <ThemeProvider theme="personal" screenMode="dark">
          <div>personal-dark</div>
        </ThemeProvider>
      </ThemeProvider>,
    );

    // root 'light' theme is normalized to 'personal'
    expect(document.documentElement).toHaveClass('np-theme-personal');

    // 'light' theme is normalized to 'personal'
    // eslint-disable-next-line testing-library/no-node-access
    expect(screen.getByText('light').parentElement).toHaveClass('np-theme-personal');
    // eslint-disable-next-line testing-library/no-node-access
    expect(screen.getByText('personal').parentElement).toHaveClass('np-theme-personal');
    // eslint-disable-next-line testing-library/no-node-access
    expect(screen.getByText('personal-dark').parentElement).toHaveClass(
      'np-theme-personal',
      'np-theme-personal--dark',
    );
  });

  it('updates theming setting based of props updates', async () => {
    const TestComponent = () => {
      const [theme, setTheme] = useState<ThemeProviderProps['theme']>('personal');
      const [screenMode, setScreenMode] = useState<ThemeProviderProps['screenMode']>('light');

      return (
        <>
          <button type="button" onClick={() => setTheme('business')}>
            Change to business
          </button>
          <button type="button" onClick={() => setScreenMode('dark')}>
            Change to dark
          </button>
          <ThemeProvider theme={theme} screenMode={screenMode}>
            <div>content</div>
          </ThemeProvider>
        </>
      );
    };

    render(<TestComponent />);

    // eslint-disable-next-line testing-library/no-node-access
    expect(screen.getByText('content').parentElement).toHaveClass('np-theme-personal');

    // Change to business theme
    fireEvent.click(screen.getByText('Change to business'));
    await waitFor(() => {
      // eslint-disable-next-line testing-library/no-node-access
      expect(screen.getByText('content').parentElement).toHaveClass(
        'np-theme-personal',
        'np-theme-business',
      );
    });

    // Change to dark mode
    fireEvent.click(screen.getByText('Change to dark'));
    await waitFor(() => {
      // eslint-disable-next-line testing-library/no-node-access
      expect(screen.getByText('content').parentElement).toHaveClass(
        'np-theme-personal',
        'np-theme-business',
        'np-theme-business--dark',
      );
    });
  });

  it('sets platform themes', () => {
    render(
      <ThemeProvider theme="personal">
        <div>personal</div>
        <ThemeProvider theme="platform">
          <div>platform</div>
        </ThemeProvider>
        <ThemeProvider theme="platform--forest-green">
          <div>platform--forest-green</div>
        </ThemeProvider>
      </ThemeProvider>,
    );

    // eslint-disable-next-line testing-library/no-node-access
    expect(screen.getByText('personal').parentElement).toHaveClass('np-theme-personal');
    // eslint-disable-next-line testing-library/no-node-access
    expect(screen.getByText('platform').parentElement).toHaveClass(
      'np-theme-personal',
      'np-theme-platform',
    );
    // eslint-disable-next-line testing-library/no-node-access
    expect(screen.getByText('platform--forest-green').parentElement).toHaveClass(
      'np-theme-personal',
      'np-theme-platform--forest-green',
    );
  });

  it('sets business themes', () => {
    render(
      <ThemeProvider theme="business">
        <div>business</div>
        <ThemeProvider theme="business" screenMode="dark">
          <div>business-dark</div>
        </ThemeProvider>
        <ThemeProvider theme="business--bright-green">
          <div>business--bright-green</div>
        </ThemeProvider>
        <ThemeProvider theme="business--forest-green">
          <div>business--forest-green</div>
        </ThemeProvider>
      </ThemeProvider>,
    );

    // eslint-disable-next-line testing-library/no-node-access
    expect(screen.getByText('business').parentElement).toHaveClass(
      'np-theme-personal',
      'np-theme-business',
    );
    // eslint-disable-next-line testing-library/no-node-access
    expect(screen.getByText('business-dark').parentElement).toHaveClass(
      'np-theme-personal',
      'np-theme-business',
      'np-theme-business--dark',
    );
    // eslint-disable-next-line testing-library/no-node-access
    expect(screen.getByText('business--bright-green').parentElement).toHaveClass(
      'np-theme-personal',
      'np-theme-business--bright-green',
    );
    // eslint-disable-next-line testing-library/no-node-access
    expect(screen.getByText('business--forest-green').parentElement).toHaveClass(
      'np-theme-personal',
      'np-theme-business--forest-green',
    );
  });
});
