import React, { useEffect, useRef, useState } from 'react';
import { render, fireEvent, waitFor, screen, cleanup } from '@testing-library/react';
import { FormHandles } from '@unform/core';
import { Form } from '@unform/web';
import { Observable } from 'rxjs';
import { InputTags } from './index';
import 'jest-styled-components';
import { IPropAutocompleteFetchResponse } from './InputTags.interface';

const fetchGroupMock = (): Observable<IPropAutocompleteFetchResponse[]> =>
   new Observable((observable) => {
      setTimeout(() => {
         observable.next([{ name: 'São Paulo' }, { name: 'Suzano' }, { name: 'Guarulhos' }]);
         observable.complete();
         observable.unsubscribe();
      }, 10);
   });

describe('Autocomplete', () => {
   it('renderizar default', () => {
      function Component(): any {
         return (
            <Form onSubmit={() => {}}>
               <InputTags fetch={fetchGroupMock} name="autocomplete" getValueText={(v) => v} />
            </Form>
         );
      }

      const { container } = render(<Component />);

      expect(container.firstChild).toMatchSnapshot();
   });

   it('renderizar valor inicial', () => {
      function Component(): any {
         return (
            <Form onSubmit={() => {}} initialData={{ autocomplete: 'Suzano' }}>
               <InputTags fetch={fetchGroupMock} name="autocomplete" getValueText={(v) => v} />
            </Form>
         );
      }

      const { container, queryByTestId } = render(<Component />);

      expect((queryByTestId('autocomplete--input') as any).value).toBe('Suzano');

      expect(container.firstChild).toMatchSnapshot();
   });

   it('renderizar abrir/fechar popup', async () => {
      function Component(): any {
         return (
            <Form onSubmit={() => {}}>
               <InputTags fetch={fetchGroupMock} name="autocomplete" getValueText={(v) => v} />
            </Form>
         );
      }

      const { container } = render(<Component />);

      fireEvent.input(screen.getByTestId('autocomplete--input'), { target: { value: 'Suzano' } });

      // Deve aparecer popup
      await waitFor(() => !!screen.getByTestId('autocomplete-list'));
      expect(screen.getByTestId('autocomplete-list--row-0').innerHTML).toEqual('<div>São Paulo</div>');
      expect(screen.getByTestId('autocomplete-list--row-1').innerHTML).toEqual('<div>Suzano</div>');
      expect(screen.getByTestId('autocomplete-list--row-2').innerHTML).toEqual('<div>Guarulhos</div>');
      expect(container.firstChild).toMatchSnapshot();

      // Deve sumir popup
      fireEvent.blur(screen.getByTestId('autocomplete--input'));

      await waitFor(() => expect(screen.queryByTestId('autocomplete-list')).toBeNull());

      expect(container.firstChild).toMatchSnapshot();
   });

   it('selecionar item popup', async () => {
      function Component(): any {
         return (
            <Form onSubmit={() => {}}>
               <InputTags fetch={fetchGroupMock} name="autocomplete" getValueText={(v) => v} />
            </Form>
         );
      }

      const { container } = render(<Component />);

      fireEvent.input(screen.getByTestId('autocomplete--input'), { target: { value: 'Suzano' } });

      // Deve aparecer popup
      await waitFor(() => !!screen.getByTestId('autocomplete-list'));
      expect(screen.getByTestId('autocomplete-list--row-0').innerHTML).toEqual('<div>São Paulo</div>');
      expect(screen.getByTestId('autocomplete-list--row-1').innerHTML).toEqual('<div>Suzano</div>');
      expect(screen.getByTestId('autocomplete-list--row-2').innerHTML).toEqual('<div>Guarulhos</div>');
      fireEvent.click(screen.getByTestId('autocomplete-list--row-2'));
      fireEvent.blur(screen.getByTestId('autocomplete--input'));

      // Esperar fechar popup
      await waitFor(() => expect(screen.queryByTestId('autocomplete-list')).toBeNull());

      await waitFor(() => expect((screen.queryByTestId('autocomplete--input') as any).value).toEqual('Guarulhos'));

      expect(container.firstChild).toMatchSnapshot();
   });

   it('renderizar with error', () => {
      function Component(): any {
         const formRef = useRef<FormHandles>();

         useEffect(() => {
            formRef.current.setFieldError('autocomplete', 'Field Invalid');
         }, []);

         return (
            <Form onSubmit={() => {}} ref={formRef}>
               <InputTags fetch={fetchGroupMock} name="autocomplete" getValueText={(v) => v} />
            </Form>
         );
      }

      const { container } = render(<Component />);

      expect(screen.getByTestId('input-error')).not.toBeUndefined();

      expect(container.firstChild).toMatchSnapshot();
   });

   it('unform - onSubmit - with initial data', () => {
      const onSubmit = jest.fn();

      function Component() {
         const formRef = useRef<FormHandles>();

         return (
            <Form ref={formRef} onSubmit={(v) => onSubmit(v)} initialData={{ autocomplete: 'initial text' }}>
               <InputTags fetch={fetchGroupMock} name="autocomplete" getValueText={(v) => v} />
               <button
                  data-testid="submit"
                  title="submit"
                  onClick={() => {
                     formRef.current.submitForm();
                  }}
               />
            </Form>
         );
      }
      render(<Component />);

      fireEvent.click(screen.getByTestId('submit'));

      expect(onSubmit).toHaveBeenCalled();
      expect(onSubmit).toHaveBeenCalledWith({ autocomplete: 'initial text' });
   });

   it('unform - onSubmit - with selected item', async () => {
      const onSubmit = jest.fn();

      function Component() {
         const formRef = useRef<FormHandles>();

         return (
            <Form ref={formRef} onSubmit={(v) => onSubmit(v)} initialData={{ autocomplete: 'initial text' }}>
               <InputTags fetch={fetchGroupMock} name="autocomplete" getValueText={(v) => v} />
               <button
                  data-testid="submit"
                  title="submit"
                  onClick={() => {
                     formRef.current.submitForm();
                  }}
               />
            </Form>
         );
      }
      render(<Component />);

      fireEvent.input(screen.getByTestId('autocomplete--input'), { target: { value: 'Suzano' } });

      // Deve aparecer popup
      await waitFor(() => !!screen.getByTestId('autocomplete-list'));
      expect(screen.getByTestId('autocomplete-list--row-0').innerHTML).toEqual('<div>São Paulo</div>');
      expect(screen.getByTestId('autocomplete-list--row-1').innerHTML).toEqual('<div>Suzano</div>');
      expect(screen.getByTestId('autocomplete-list--row-2').innerHTML).toEqual('<div>Guarulhos</div>');
      fireEvent.click(screen.getByTestId('autocomplete-list--row-2'));
      fireEvent.blur(screen.getByTestId('autocomplete--input'));

      // Esperar fechar popup
      await waitFor(() => expect(screen.queryByTestId('autocomplete-list')).toBeNull());

      fireEvent.click(screen.getByTestId('submit'));

      expect(onSubmit).toHaveBeenCalled();
      expect(onSubmit).toHaveBeenCalledWith({ autocomplete: 'Guarulhos' });
   });
});
