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 '.';
import 'jest-styled-components';
import { IAutocompleteItem } from '../AutocompletePure';

const fetchExample = (): Observable<IAutocompleteItem[]> =>
   new Observable((observable) => {
      setTimeout(() => {
         observable.next([
            { name: 'Star Platinum', value: 1 },
            { name: "Magician's Red", value: 2 },
            { name: 'Hermit Purple', value: 3 },
            { name: 'Hierophant Green', value: 4 },
            { name: 'Silver Chariot', value: 5 },
            { name: 'The Fool', value: 6 },
            { name: 'The World', value: 7 },
            { name: 'Tower of Gray', value: 8 },
            { name: 'Dark Blue Moon', value: 9 },
            { name: 'Strength', value: 10 },
            { name: 'Ebony Devil', value: 11 },
            { name: 'Yellow Temperance', value: 12 },
            { name: 'Hanged Man', value: 13 },
            { name: 'Emperor', value: 14 },
            { name: 'Empress', value: 15 },
            { name: 'Wheel of Fortune', value: 16 },
            { name: 'Justice', value: 17 },
            { name: 'Lovers', value: 18 },
            { name: 'Sun', value: 19 },
         ]);
         observable.complete();
         observable.unsubscribe();
      }, 100);
   });

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

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

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

   it('renderizar valor inicial', () => {
      function Component(): any {
         return (
            <Form
               onSubmit={() => {}}
               initialData={{
                  autocomplete: [
                     {
                        name: 'The World',
                        value: 7,
                     },
                     { name: "Magician's Red", value: 2 },
                  ],
               }}
            >
               <InputTags fetchItems={fetchExample} name="autocomplete" />
            </Form>
         );
      }

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

      expect((queryByTestId('tag-0') as any).innerHTML).toContain('The World');
      expect((queryByTestId('tag-1') as any).innerHTML).toContain("Magician's Red");

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

   it('renderizar abrir/fechar popup', async () => {
      function Component(): any {
         return (
            <Form onSubmit={() => {}}>
               <InputTags 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('Star Platinum');
      expect(screen.getByTestId('autocomplete-list--row-1').innerHTML).toContain("Magician's Red");
      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 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('Star Platinum');
      expect(screen.getByTestId('autocomplete-list--row-1').innerHTML).toContain("Magician's Red");
      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}>
               <InputTags fetchItems={fetchExample} name="autocomplete" />
            </Form>
         );
      }

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

      expect(screen.getByTestId('input-error')).not.toBeUndefined();
      expect(screen.getByTestId('input-error').innerHTML).toContain('Field Invalid');

      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' }}>
               <InputTags 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('Star Platinum');
      expect(screen.getByTestId('autocomplete-list--row-1').innerHTML).toContain("Magician's Red");
      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: [
                     { name: 'The World', value: 7 },
                     { name: "Magician's Red", value: 2 },
                  ],
               }}
            >
               <InputTags fetchItems={fetchExample} name="autocomplete" cleanAfterSelect />
               <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: [
            { name: 'The World', value: 7 },
            { name: "Magician's Red", value: 2 },
         ],
      });
   });

   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: [] }}>
               <InputTags 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('Star Platinum');
      expect(screen.getByTestId('autocomplete-list--row-1').innerHTML).toContain("Magician's Red");
      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: [{ name: 'Hermit Purple', value: 3 }] });
   });

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

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

         return (
            <Form
               ref={formRef}
               onSubmit={(v) => onSubmit(v)}
               initialData={{ autocomplete: [{ name: 'Silver Chariot', value: 5 }] }}
            >
               <InputTags 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('Star Platinum');
      expect(screen.getByTestId('autocomplete-list--row-1').innerHTML).toContain("Magician's Red");
      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: [
            { name: 'Silver Chariot', value: 5 },
            { name: 'Hermit Purple', value: 3 },
         ],
      });
   });

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

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

         function updateTags(): void {
            formRef.current.setData({
               autocomplete: [
                  {
                     name: 'The World',
                     value: 7,
                  },
                  { name: "Magician's Red", value: 2 },
               ],
            });
         }

         return (
            <Form
               ref={formRef}
               onSubmit={(v) => onSubmit(v)}
               initialData={{ autocomplete: [{ name: 'Silver Chariot', value: 5 }] }}
            >
               <InputTags fetchItems={fetchExample} name="autocomplete" cleanAfterSelect />
               <button onClick={updateTags} type="button" data-testid="update" />
               <button
                  data-testid="submit"
                  title="submit"
                  onClick={() => {
                     formRef.current.submitForm();
                  }}
               />
            </Form>
         );
      }
      const { queryByTestId } = render(<Component />);

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

      expect((queryByTestId('tag-0') as any).innerHTML).toContain('The World');
      expect((queryByTestId('tag-1') as any).innerHTML).toContain("Magician's Red");

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

      expect(onSubmit).toHaveBeenCalled();
      expect(onSubmit).toHaveBeenCalledWith({
         autocomplete: [
            {
               name: 'The World',
               value: 7,
            },
            { name: "Magician's Red", value: 2 },
         ],
      });
   });
});
