import * as React from 'react';
import {
  render,
  screen
} from '@testing-library/react';
import '@testing-library/jest-dom';
import userEvent from '@testing-library/user-event';
import * as TextControlBase from '@tesseract-design/web-base-textcontrol';
import {
  TextInput, TextInputType,
} from '.';

jest.mock('@tesseract-design/web-base-textcontrol');

describe('TextInput', () => {
  it('should render a textbox', () => {
    render(
      <TextInput />
    );
    const textbox = screen.getByRole('textbox');
    expect(textbox).toBeInTheDocument();
    expect(textbox).toHaveProperty('type', 'text');
  });

  it('should render a border', () => {
    render(
      <TextInput
        border
      />
    );
    const border = screen.getByTestId('border');
    expect(border).toBeInTheDocument();
  });

  it('should render a label', () => {
    render(
      <TextInput
        label="foo"
      />
    );
    const textbox = screen.getByLabelText('foo');
    expect(textbox).toBeInTheDocument();
    const label = screen.getByTestId('label');
    expect(label).toHaveTextContent('foo');
  });

  it('should render a hidden label', () => {
    render(
      <TextInput
        label="foo"
        hiddenLabel
      />
    );
    const textbox = screen.getByLabelText('foo');
    expect(textbox).toBeInTheDocument();
    const label = screen.queryByTestId('label');
    expect(label).toBeNull();
  });

  it('should render a hint', () => {
    render(
      <TextInput
        hint="foo"
      />
    );
    const hint = screen.getByTestId('hint');
    expect(hint).toBeInTheDocument();
  });

  it('should render an indicator', () => {
    render(
      <TextInput
        indicator={
          <div data-testid="indicator" />
        }
      />
    );
    const indicator = screen.getByTestId('indicator');
    expect(indicator).toBeInTheDocument();
  });

  describe.each([
    TextControlBase.TextControlSize.SMALL,
    TextControlBase.TextControlSize.MEDIUM,
    TextControlBase.TextControlSize.LARGE,
  ])('on %s size', (size) => {
    it('should render input styles', () => {
      render(
        <TextInput
          size={size}
        />
      );

      expect(TextControlBase.Input).toBeCalledWith(expect.objectContaining({
        size,
      }));
    });

    it('should render hint styles', () => {
      render(
        <TextInput
          size={size}
          hint="hint"
        />
      );

      expect(TextControlBase.HintWrapper).toBeCalledWith(expect.objectContaining({
        size,
      }));
    });

    it('should render indicator styles', () => {
      render(
        <TextInput
          size={size}
          indicator={
            <div data-testid="indicator" />
          }
        />
      );

      expect(TextControlBase.IndicatorWrapper).toBeCalledWith(expect.objectContaining({
        size,
      }));
    });
  });

  it('should render a block textbox', () => {
    render(
      <TextInput
        block
      />
    );

    expect(TextControlBase.Root).toBeCalledWith(expect.objectContaining({
      block: true,
    }));
  });

  it.each([
    TextInputType.TEXT,
    TextInputType.SEARCH,
  ])('should render a textbox with type %s', (buttonType) => {
    render(
      <TextInput
        type={buttonType}
      />
    );
    const textbox: HTMLButtonElement = screen.getByTestId('input');
    expect(textbox).toHaveProperty('type', buttonType);
  });

  describe.each([
    TextControlBase.TextControlStyle.DEFAULT,
    TextControlBase.TextControlStyle.ALTERNATE,
  ])('on %s style', (style) => {
    it('should render input styles', () => {
      render(
        <TextInput
          style={style}
        />
      );

      expect(TextControlBase.Input).toBeCalledWith(expect.objectContaining({
        style,
      }));
    });

    it('should render hint styles', () => {
      render(
        <TextInput
          style={style}
          hint="hint"
        />
      );

      expect(TextControlBase.HintWrapper).toBeCalledWith(expect.objectContaining({
        style,
      }));
    });

    it('should render indicator styles', () => {
      render(
        <TextInput
          style={style}
          indicator={
            <div
              data-testid="indicator"
            />
          }
        />
      );

      expect(TextControlBase.IndicatorWrapper).toBeCalledWith(expect.objectContaining({
        style,
      }));
    });
  });

  it('should handle change events', () => {
    const onChange = jest.fn();
    render(
      <TextInput
        onChange={onChange}
      />
    );
    const textbox: HTMLInputElement = screen.getByRole('textbox');
    userEvent.type(textbox, 'foobar');
    expect(onChange).toBeCalled();
  });
});
