import React from 'react';

import '@testing-library/jest-dom';
import { fireEvent, render } from '@testing-library/react';

import { noop } from 'utils/common';

import { THEME } from '../../constants';
import { Select, selectClassName } from './Select';
import {
  defaultDropdownClassName,
  defaultOptionClassName,
  defaultPopperClassName,
  defaultTriggerClassName,
} from './components';
import { SelectOption, SelectProps, SELECT_TYPE } from './types';

const targetOption = { id: 1, label: 'Option 1' };

const defaultSelectProps: SelectProps<SelectOption> = {
  variant: SELECT_TYPE.default,
  value: targetOption.id,
  options: [{ id: 0, label: 'Option' }, targetOption, { id: 2, label: 'Option 2' }],
  onChange: noop,
};

describe('Select', () => {
  test('render selected option label', () => {
    const { container } = render(<Select {...defaultSelectProps} />);

    const selectValue = container.querySelector(`.${defaultTriggerClassName('value')}`);
    expect(selectValue).toHaveTextContent(targetOption.label);
  });

  test('render dropdown', () => {
    const { container } = render(
      <Select
        {...defaultSelectProps}
        isInitiallyOpened
      />,
    );

    const selectDropdown = container.querySelector(`.${defaultPopperClassName(null)}`);
    expect(selectDropdown).not.toBeNull();
  });

  test('render all passed options', () => {
    const { container } = render(
      <Select
        {...defaultSelectProps}
        isInitiallyOpened
      />,
    );

    const selectDropdown = container.querySelector(`.${defaultDropdownClassName(null)}`);
    const selectOptions = selectDropdown?.querySelectorAll(`.${defaultOptionClassName(null)}`);
    expect(selectOptions).toHaveLength(defaultSelectProps.options.length);
  });

  test('render select label', () => {
    const label = 'Select label';
    const { container } = render(
      <Select
        {...defaultSelectProps}
        label={label}
      />,
    );

    const selectLabel = container.querySelector(`.${selectClassName('label')}`);
    expect(selectLabel).toHaveTextContent(label);
  });

  test('render select error message', () => {
    const error = 'Select error message';
    const { container } = render(
      <Select
        {...defaultSelectProps}
        error={error}
      />,
    );

    const selectError = container.querySelector(`.${selectClassName('error')}`);
    expect(selectError).toHaveTextContent(error);
  });

  test('render placeholder text', () => {
    const placeholder = 'Custom select placeholder message';
    const { container } = render(
      <Select
        {...defaultSelectProps}
        value={null}
        placeholder={placeholder}
      />,
    );

    const selectPlaceholder = container.querySelector(`.${defaultTriggerClassName('placeholder')}`);
    expect(selectPlaceholder).toHaveTextContent(placeholder);
  });

  test('render search input if search enabled', () => {
    const { container } = render(
      <Select
        {...defaultSelectProps}
        isInitiallyOpened
        isSearchable
      />,
    );

    const selectSearchInput = container.querySelector(`.${defaultPopperClassName('search')}`);
    expect(selectSearchInput).not.toBeNull();
  });

  test('render disabled select', () => {
    const { container } = render(
      <Select
        {...defaultSelectProps}
        isDisabled
      />,
    );

    const selectTrigger = container.querySelector(`.${defaultTriggerClassName(null)}`);
    expect(selectTrigger).toBeDisabled();
    expect(selectTrigger).toHaveClass(defaultTriggerClassName(null, { isDisabled: true }));
  });

  test('render search input if search enabled', () => {
    const { container } = render(
      <Select
        {...defaultSelectProps}
        isInitiallyOpened
        isSearchable
      />,
    );

    const selectSearchInput = container.querySelector(`.${defaultPopperClassName('search')}`);
    expect(selectSearchInput).not.toBeNull();
  });

  test('filter options if search filled', () => {
    const { container } = render(
      <Select
        {...defaultSelectProps}
        isInitiallyOpened
        isSearchable
      />,
    );

    const selectSearchInput = container.querySelector(`.${defaultPopperClassName('search')} > input`);

    if (selectSearchInput) {
      fireEvent.change(selectSearchInput, { target: { value: targetOption.label.toLowerCase() } });
    } else {
      expect(selectSearchInput).toThrow('Search field does not exist');
    }

    const FILTERED_OPTIONS_LENGTH = 1;
    const selectDropdown = container.querySelector(`.${defaultDropdownClassName(null)}`);
    const selectOptions = selectDropdown?.querySelectorAll(`.${defaultOptionClassName(null)}`);
    expect(selectOptions).toHaveLength(FILTERED_OPTIONS_LENGTH);
  });

  test('render themed select', () => {
    const { container } = render(
      <Select
        {...defaultSelectProps}
        theme={THEME.dark}
      />,
    );

    const select = container.querySelector(`.${selectClassName(null)}`);
    expect(select).toHaveClass(selectClassName(null, { [THEME.dark]: true }));
  });

  test('render compact select variant', () => {
    const { container } = render(
      <Select
        {...defaultSelectProps}
        variant={SELECT_TYPE.compact}
      />,
    );

    const select = container.querySelector(`.${selectClassName(null)}`);
    expect(select).toHaveClass(selectClassName(null, { isCompact: true }));
  });
});
