import React, { useEffect, useRef, useState } from 'react';
import renderer from 'react-test-renderer';
import { render, fireEvent, waitFor, screen } from '@testing-library/react';
import { FormHandles } from '@devesharp/unform-core';
import { Form } from '@devesharp/unform-web';
import 'jest-styled-components';
import { AppProvider } from '../AppProvider';
import { CustomComponentInput } from './__mocks__/InputCustom';
import { Input } from './Input';

describe('Input', () => {
   it('snapshot - default', () => {
      const tree = renderer
         .create(
            <>
               <Form onSubmit={() => {}}>
                  <Input name="default" />
               </Form>
            </>,
         )
         .toJSON();
      expect(tree).toMatchSnapshot();
   });

   it('snapshot - prefix with JSX', () => {
      const tree = renderer
         .create(
            <>
               <Form onSubmit={() => {}}>
                  <Input name="default" prefix={<i className="fas fa-user" />} />
               </Form>
            </>,
         )
         .toJSON();
      expect(tree).toMatchSnapshot();
   });

   it('snapshot - prefix with text', () => {
      const tree = renderer
         .create(
            <>
               <Form onSubmit={() => {}}>
                  <Input name="default" prefix="R$" />
               </Form>
            </>,
         )
         .toJSON();
      expect(tree).toMatchSnapshot();
   });

   it('snapshot - suffix with JSX', () => {
      const tree = renderer
         .create(
            <>
               <Form onSubmit={() => {}}>
                  <Input name="default" suffix={<i className="fas fa-user" />} />
               </Form>
            </>,
         )
         .toJSON();
      expect(tree).toMatchSnapshot();
   });

   it('snapshot - suffix with text', () => {
      const tree = renderer
         .create(
            <>
               <Form onSubmit={() => {}}>
                  <Input name="default" suffix="R$" />
               </Form>
            </>,
         )
         .toJSON();
      expect(tree).toMatchSnapshot();
   });

   it('snapshot - with type hidden', () => {
      const tree = renderer
         .create(
            <>
               <Form onSubmit={() => {}}>
                  <Input name="default" type="hidden" />
               </Form>
            </>,
         )
         .toJSON();
      expect(tree).toMatchSnapshot();
   });

   it('snapshot - title', () => {
      const tree = renderer
         .create(
            <>
               <Form onSubmit={() => {}}>
                  <Input name="default" title="Full Name" />
               </Form>
            </>,
         )
         .toJSON();
      expect(tree).toMatchSnapshot();
   });

   it('snapshot - with password', () => {
      const tree = renderer
         .create(
            <>
               <Form onSubmit={() => {}}>
                  <Input name="default" title="Full Name" password />
               </Form>
            </>,
         )
         .toJSON();
      expect(tree).toMatchSnapshot();
   });

   it('snapshot - textRight', () => {
      const tree = renderer
         .create(
            <>
               <Form onSubmit={() => {}} initialData={{ default: 'text-right' }}>
                  <Input name="default" textRight />
               </Form>
            </>,
         )
         .toJSON();
      expect(tree).toMatchSnapshot();
   });

   it('snapshot - with number', () => {
      const tree = renderer
         .create(
            <>
               <Form onSubmit={() => {}} initialData={{ default: '10000' }}>
                  <Input name="default" mask="number" />
               </Form>
            </>,
         )
         .toJSON();
      expect(tree).toMatchSnapshot();
   });

   it('snapshot - with number decimals', () => {
      const tree = renderer
         .create(
            <>
               <Form onSubmit={() => {}} initialData={{ default: '10000' }}>
                  <Input name="default" mask="number" decimals={4} />
               </Form>
            </>,
         )
         .toJSON();
      expect(tree).toMatchSnapshot();
   });

   it('snapshot - with CEP', () => {
      const tree = renderer
         .create(
            <>
               <Form onSubmit={() => {}} initialData={{ default: '08871220' }}>
                  <Input name="default" mask="CEP" />
               </Form>
            </>,
         )
         .toJSON();
      expect(tree).toMatchSnapshot();
   });

   it('snapshot - with CNPJ', () => {
      const tree = renderer
         .create(
            <>
               <Form onSubmit={() => {}} initialData={{ default: '26576255000191' }}>
                  <Input name="default" mask="CNPJ" />
               </Form>
            </>,
         )
         .toJSON();
      expect(tree).toMatchSnapshot();
   });

   it('snapshot - with CPF', () => {
      const tree = renderer
         .create(
            <>
               <Form onSubmit={() => {}} initialData={{ default: '26576255000191' }}>
                  <Input name="default" mask="CPF" />
               </Form>
            </>,
         )
         .toJSON();
      expect(tree).toMatchSnapshot();
   });

   it('snapshot - with RG', () => {
      const tree = renderer
         .create(
            <>
               <Form onSubmit={() => {}} initialData={{ default: '461273317' }}>
                  <Input name="default" mask="RG" />
               </Form>
            </>,
         )
         .toJSON();
      expect(tree).toMatchSnapshot();
   });

   it('snapshot - with phone', () => {
      const tree = renderer
         .create(
            <>
               <Form onSubmit={() => {}} initialData={{ default: '1188881234', number11Digits: '11988881234' }}>
                  <Input name="default" mask="phone" />
                  <Input name="number11Digits" mask="phone" />
               </Form>
            </>,
         )
         .toJSON();
      expect(tree).toMatchSnapshot();
   });

   it('snapshot - no spaces', () => {
      const tree = renderer
         .create(
            <>
               <Form onSubmit={() => {}} initialData={{ default: ' email @simple. com. br' }}>
                  <Input name="default" mask="no-spaces" />
               </Form>
            </>,
         )
         .toJSON();
      expect(tree).toMatchSnapshot();
   });

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

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

         return (
            <>
               <Form onSubmit={() => {}} initialData={{ default: 'default' }} ref={formRef}>
                  <Input name="default" />
               </Form>
            </>
         );
      }

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

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

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

   it('snapshot - with CustomComponent', () => {
      const { container } = render(<Input title="Custom Input" CustomComponent={CustomComponentInput} />);

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

   it('snapshot - with CustomComponent in AppProvider', () => {
      const { container } = render(
         <AppProvider initialData={{ customComponents: { Input: CustomComponentInput } }}>
            <Input title="Custom Input" />
         </AppProvider>,
      );

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

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

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

         return (
            <Form ref={formRef} onSubmit={(v) => onSubmit(v)} initialData={{ default: 100.2212 }}>
               <Input name="default" mask="number" decimals={4} />
               <button
                  data-testid="submit"
                  title="submit"
                  onClick={() => {
                     formRef.current.submitForm();
                  }}
               />
            </Form>
         );
      }
      render(<Component />);

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

      expect(onSubmit).toHaveBeenCalled();
      expect(onSubmit).toHaveBeenCalledWith({ default: 100.2212 });
   });

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

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

         return (
            <Form ref={formRef} onSubmit={(v) => onSubmit(v)} initialData={{ default: '100,00' }}>
               <Input name="default" mask="number" />
               <button
                  data-testid="submit"
                  title="submit"
                  onClick={() => {
                     formRef.current.submitForm();
                  }}
               />
            </Form>
         );
      }
      render(<Component />);

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

      expect(onSubmit).toHaveBeenCalled();
      expect(onSubmit).toHaveBeenCalledWith({ default: 100 });
   });

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

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

         return (
            <Form ref={formRef} onSubmit={(v) => onSubmit(v)} initialData={{ default: '1.0000' }}>
               <Input name="default" mask="number" decimals={4} />
               <button
                  data-testid="submit"
                  title="submit"
                  onClick={() => {
                     formRef.current.submitForm();
                  }}
               />
            </Form>
         );
      }
      render(<Component />);

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

      expect(onSubmit).toHaveBeenCalled();
      expect(onSubmit).toHaveBeenCalledWith({ default: 1 });
   });

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

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

         return (
            <Form ref={formRef} onSubmit={(v) => onSubmit(v)} initialData={{ default: '08871-220' }}>
               <Input name="default" mask="CEP" />
               <button
                  data-testid="submit"
                  title="submit"
                  onClick={() => {
                     formRef.current.submitForm();
                  }}
               />
            </Form>
         );
      }
      render(<Component />);

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

      expect(onSubmit).toHaveBeenCalled();
      expect(onSubmit).toHaveBeenCalledWith({ default: '08871220' });
   });

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

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

         return (
            <Form ref={formRef} onSubmit={(v) => onSubmit(v)} initialData={{ default: '26576255000191' }}>
               <Input name="default" mask="CNPJ" />
               <button
                  data-testid="submit"
                  title="submit"
                  onClick={() => {
                     formRef.current.submitForm();
                  }}
               />
            </Form>
         );
      }
      render(<Component />);

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

      expect(onSubmit).toHaveBeenCalled();
      expect(onSubmit).toHaveBeenCalledWith({ default: '26.576.255/0001-91' });
   });

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

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

         return (
            <Form ref={formRef} onSubmit={(v) => onSubmit(v)} initialData={{ default: '265.762.550-00' }}>
               <Input name="default" mask="CPF" />
               <button
                  data-testid="submit"
                  title="submit"
                  onClick={() => {
                     formRef.current.submitForm();
                  }}
               />
            </Form>
         );
      }
      render(<Component />);

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

      expect(onSubmit).toHaveBeenCalled();
      expect(onSubmit).toHaveBeenCalledWith({ default: '26576255000' });
   });

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

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

         return (
            <Form ref={formRef} onSubmit={(v) => onSubmit(v)} initialData={{ default: '461273317' }}>
               <Input name="default" mask="RG" />
               <button
                  data-testid="submit"
                  title="submit"
                  onClick={() => {
                     formRef.current.submitForm();
                  }}
               />
            </Form>
         );
      }
      render(<Component />);

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

      expect(onSubmit).toHaveBeenCalled();
      expect(onSubmit).toHaveBeenCalledWith({ default: '46.127.331-7' });
   });

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

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

         return (
            <Form
               ref={formRef}
               onSubmit={(v) => onSubmit(v)}
               initialData={{ default: '(11) 8888-1234', number11Digits: '11988881234' }}
            >
               <Input name="default" mask="phone" />
               <Input name="number11Digits" mask="phone" />
               <button
                  data-testid="submit"
                  title="submit"
                  onClick={() => {
                     formRef.current.submitForm();
                  }}
               />
            </Form>
         );
      }
      render(<Component />);

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

      expect(onSubmit).toHaveBeenCalled();
      expect(onSubmit).toHaveBeenCalledWith({ default: '1188881234', number11Digits: '11988881234' });
   });

   it('unform - onSubmit - no spaces', () => {
      const onSubmit = jest.fn();

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

         return (
            <Form ref={formRef} onSubmit={(v) => onSubmit(v)} initialData={{ default: ' email @simple. com. br' }}>
               <Input name="default" mask="no-spaces" />
               <button
                  data-testid="submit"
                  title="submit"
                  type="button"
                  onClick={() => {
                     formRef.current.submitForm();
                  }}
               />
            </Form>
         );
      }
      render(<Component />);

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

      expect(onSubmit).toHaveBeenCalled();
      expect(onSubmit).toHaveBeenCalledWith({ default: 'email@simple.com.br' });
   });
});
