import React from 'react';

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

import { Slider } from './Slider';

import sliderStyles from './slider.scss';

describe('Slider', () => {
  const TWO_THUMBS = 2;
  const ONE_THUMB = 1;

  test('receives defaultValue property as Number and renders default state', () => {
    const { container } = render(
      <Slider
        defaultValue={10}
        onAfterChange={(): void => {}}
      />,
    );

    const slider = container.querySelector('div');
    const track = slider?.querySelector(`.${sliderStyles['slider__track']}`);
    const thumbs = slider?.querySelectorAll(`.${sliderStyles['slider__thumb']}`) ?? [];

    expect(slider).toHaveClass(sliderStyles['slider']);
    expect(track).not.toBeFalsy();
    expect(thumbs).toHaveLength(ONE_THUMB);

    thumbs.forEach((thumb) => {
      expect(thumb).not.toBeFalsy();
    });
  });

  test('receives defaultValue property as an Array and renders default state', () => {
    const minThumbValue = 1;
    const maxThumbValue = 4;
    const thumbsDefaultValue = [minThumbValue, maxThumbValue];
    const { container } = render(
      <Slider
        min={0}
        max={5}
        step={1}
        defaultValue={thumbsDefaultValue}
        onAfterChange={(): void => {}}
      />,
    );

    const slider = container.querySelector('div');
    const track = slider?.querySelector(`.${sliderStyles['slider__track']}`);
    const thumbs = slider?.querySelectorAll(`.${sliderStyles['slider__thumb']}`) ?? [];

    expect(slider).toHaveClass(sliderStyles['slider']);
    expect(track).not.toBeFalsy();
    expect(thumbs).toHaveLength(TWO_THUMBS);

    thumbs.forEach((thumb) => {
      expect(thumb).not.toBeFalsy();
    });
  });

  test('does not render labels on thumbs, if stepValues are not set', () => {
    const minThumbValue = 1;
    const maxThumbValue = 2;
    const thumbsDefaultValue = [minThumbValue, maxThumbValue];
    const { container } = render(
      <Slider
        min={1}
        max={3}
        step={1}
        defaultValue={thumbsDefaultValue}
        onAfterChange={(): void => {}}
      />,
    );

    const slider = container.querySelector('div');
    const track = slider?.querySelector(`.${sliderStyles['slider__track']}`);
    const thumbs = slider?.querySelectorAll(`.${sliderStyles['slider__thumb']}`) ?? [];

    expect(slider).toHaveClass(sliderStyles['slider']);
    expect(track).not.toBeFalsy();
    expect(thumbs).toHaveLength(TWO_THUMBS);

    thumbs.forEach((thumb) => {
      const thumbText = thumb.querySelector(`.${sliderStyles['slider__thumb-text']}`);

      expect(thumbText).toBeEmptyDOMElement();
    });
  });

  test('renders labels on thumbs, if stepValues are set', () => {
    const minSliderValue = 0;
    const minThumbValue = 1;
    const maxThumbValue = 2;
    const maxSliderValue = 3;

    const minSliderValueLabel = 'min slider value';
    const minThumbValueLabel = 'first thumb value';
    const maxThumbValueLabel = 'second thumb value';
    const maxSliderValueLabel = 'max slider value';

    const thumbsDefaultValue = [minThumbValue, maxThumbValue];

    const stepValues = [
      { label: minSliderValueLabel, value: minSliderValue },
      { label: minThumbValueLabel, value: minThumbValue },
      { label: maxThumbValueLabel, value: maxThumbValue },
      { label: maxSliderValueLabel, value: maxSliderValue },
    ];

    const { container } = render(
      <Slider
        min={0}
        max={3}
        defaultValue={thumbsDefaultValue}
        onAfterChange={(): void => {}}
        stepValues={stepValues}
      />,
    );

    const slider = container.querySelector('div');
    const track = slider?.querySelector(`.${sliderStyles['slider__track']}`);
    const thumbs = slider?.querySelectorAll(`.${sliderStyles['slider__thumb']}`) ?? [];

    expect(slider).toHaveClass(sliderStyles['slider']);
    expect(track).not.toBeFalsy();
    expect(thumbs).toHaveLength(TWO_THUMBS);

    thumbs.forEach((thumb, index) => {
      const thumbText = thumb.querySelector(`.${sliderStyles['slider__thumb-text']}`);
      const firstThumbIndex = 0;
      let label: string;

      if (index === firstThumbIndex) {
        label = minThumbValueLabel;
      } else {
        label = maxThumbValueLabel;
      }

      expect(thumbText).toHaveTextContent(label);
    });
  });

  test('renders disabled Slider element and its controls', () => {
    const { container } = render(
      <Slider
        disabled={true}
        onAfterChange={(): void => {}}
      />,
    );

    const slider = container.querySelector('div');
    const track = slider?.querySelector(`.${sliderStyles['slider__track']}`);
    const thumbs = slider?.querySelectorAll(`.${sliderStyles['slider__thumb']}`) ?? [];

    expect(slider).toHaveClass(sliderStyles['slider--isDisabled']);
    expect(track).toHaveClass(sliderStyles['slider__track--isDisabled']);
    expect(thumbs).toHaveLength(ONE_THUMB);

    thumbs.forEach((thumb) => {
      expect(thumb).toHaveClass(sliderStyles['slider__thumb--isDisabled']);
    });
  });

  test('receives classNamesOverrides properties and extends Slider elements class names', () => {
    const minSliderValue = 0;
    const minThumbValue = 1;
    const maxThumbValue = 2;
    const maxSliderValue = 3;

    const minSliderValueLabel = 'min slider value';
    const minThumbValueLabel = 'first thumb value';
    const maxThumbValueLabel = 'second thumb value';
    const maxSliderValueLabel = 'max slider value';

    const thumbsDefaultValue = [minThumbValue, maxThumbValue];

    const stepValues = [
      { label: minSliderValueLabel, value: minSliderValue },
      { label: minThumbValueLabel, value: minThumbValue },
      { label: maxThumbValueLabel, value: maxThumbValue },
      { label: maxSliderValueLabel, value: maxSliderValue },
    ];

    const externalClassNames = {
      thumb: 'thumb--overrides',
      thumbText: 'thumb__text--overrides',
      track: 'track--overrides',
      slider: 'slider--overrides',
    };

    const { container } = render(
      <Slider
        min={0}
        max={3}
        defaultValue={thumbsDefaultValue}
        onAfterChange={(): void => {}}
        stepValues={stepValues}
        classNamesOverrides={externalClassNames}
      />,
    );

    const slider = container.querySelector('div');
    const track = slider?.querySelector(`.${sliderStyles['slider__track']}`);
    const thumbs = slider?.querySelectorAll(`.${sliderStyles['slider__thumb']}`) ?? [];

    expect(slider).toHaveClass(`${sliderStyles['slider']} ${externalClassNames.slider}`);

    expect(track).not.toBeFalsy();
    expect(track).toHaveClass(`${sliderStyles['slider__track']} ${externalClassNames.track}`);

    expect(thumbs).toHaveLength(TWO_THUMBS);

    thumbs.forEach((thumb) => {
      expect(thumb).not.toBeFalsy();
      expect(thumb).toHaveClass(`${sliderStyles['slider__thumb']} ${externalClassNames.thumb}`);

      const thumbText = thumb.querySelector(`.${sliderStyles['slider__thumb-text']}`);
      expect(thumbText).toHaveClass(`${sliderStyles['slider__thumb-text']} ${externalClassNames.thumbText}`);
    });
  });
});
