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

const fetchExample = (): Observable<IAutocompleteItem[]> =>
   new Observable((observable) => {
      setTimeout(() => {
         observable.next([
            { name: 'Bairro', disabled: true, value: { title: true } },
            { name: 'Mogi das cruzes', value: 1 },
            { name: 'Suzano', value: 2 },
            { name: 'Cidade', disabled: true, value: { title: true } },
            { name: 'São Paulo', value: 3 },
            { name: 'Suzano', value: 4 },
            { name: 'Guarulhos', value: 5 },
         ]);
         observable.complete();
         observable.unsubscribe();
      }, 100);
   });

describe('Autocomplete', () => {
   it('renderizar default', () => {
      function Component(): any {
         return (
            <Form onSubmit={() => {}}>
               <Autocomplete fetchItems={fetchExample} />
            </Form>
         );
      }

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

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

   it('renderizar valor inicial', () => {
      function Component(): any {
         return (
            <Form onSubmit={() => {}} initialData={{ autocomplete: 'Suzano' }}>
               <Autocomplete fetchItems={fetchExample} name="autocomplete" />
            </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={() => {}}>
               <Autocomplete fetchItems={fetchExample} name="autocomplete" />
            </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).toContain('Bairro');
      expect(screen.getByTestId('autocomplete-list--row-1').innerHTML).toContain('Mogi das cruzes');
      expect(screen.getByTestId('autocomplete-list--row-2').innerHTML).toContain('Suzano');
      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={() => {}}>
               <Autocomplete fetchItems={fetchExample} name="autocomplete" />
            </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).toContain('Bairro');
      expect(screen.getByTestId('autocomplete-list--row-1').innerHTML).toContain('Mogi das cruzes');
      expect(screen.getByTestId('autocomplete-list--row-2').innerHTML).toContain('Suzano');
      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('Suzano'));

      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}>
               <Autocomplete fetchItems={fetchExample} name="autocomplete" />
            </Form>
         );
      }

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

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

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

   it('with cleanAfterSelect', async () => {
      const onSubmit = jest.fn();

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

         return (
            <Form ref={formRef} onSubmit={(v) => onSubmit(v)} initialData={{ autocomplete: 'initial text' }}>
               <Autocomplete fetchItems={fetchExample} name="autocomplete" cleanAfterSelect />
               <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).toContain('Bairro');
      expect(screen.getByTestId('autocomplete-list--row-1').innerHTML).toContain('Mogi das cruzes');
      expect(screen.getByTestId('autocomplete-list--row-2').innerHTML).toContain('Suzano');
      fireEvent.click(screen.getByTestId('autocomplete-list--row-2'));
      fireEvent.blur(screen.getByTestId('autocomplete--input'));

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

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

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

         return (
            <Form ref={formRef} onSubmit={(v) => onSubmit(v)} initialData={{ autocomplete: 'initial text' }}>
               <Autocomplete fetchItems={fetchExample} name="autocomplete" />
               <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(): any {
         const formRef = useRef<FormHandles>();

         return (
            <Form ref={formRef} onSubmit={(v) => onSubmit(v)} initialData={{ autocomplete: 'initial text' }}>
               <Autocomplete fetchItems={fetchExample} name="autocomplete" />
               <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).toContain('Bairro');
      expect(screen.getByTestId('autocomplete-list--row-1').innerHTML).toContain('Mogi das cruzes');
      expect(screen.getByTestId('autocomplete-list--row-2').innerHTML).toContain('Suzano');
      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: 'Suzano' });
   });
});
