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

describe('Select', () => {
   it('snapshot - with options', () => {
      function Component(): any {
         return (
            <Form onSubmit={() => {}}>
               <Select name="default">
                  <option value="Eren">Eren</option>
                  <option value="Levi">Levi</option>
                  <option value="Rainer">Rainer</option>
                  <option value="Falco">Falco</option>
               </Select>
            </Form>
         );
      }

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

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

   it('snapshot - default', () => {
      function Component(): any {
         return (
            <Form onSubmit={() => {}}>
               <Select
                  name="default"
                  options={[
                     { value: 'M', name: 'Male' },
                     { value: 'F', name: 'Female' },
                     { value: 'D', name: 'Disabled', disabled: true },
                  ]}
               />
            </Form>
         );
      }

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

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

   it('snapshot - with color', () => {
      function Component(): any {
         return (
            <Form onSubmit={() => {}} initialData={{ checkbox: true }}>
               <Select
                  color="orange"
                  name="radio"
                  options={[
                     { value: 'M', name: 'Male' },
                     { value: 'F', name: 'Female' },
                     { value: 'D', name: 'Disabled', disabled: true },
                  ]}
               />
            </Form>
         );
      }

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

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

   it('snapshot - with object value', () => {
      function Component(): any {
         return (
            <>
               <Form onSubmit={() => {}} initialData={{ radio: { id: 'F' } }}>
                  <Select
                     color="red"
                     name="radio"
                     options={[
                        { value: { id: 'M' }, name: 'Male' },
                        { value: { id: 'F' }, name: 'Female' },
                        { value: { id: 'D' }, name: 'Disabled', disabled: true },
                     ]}
                  />
               </Form>
               <Form onSubmit={() => {}} initialData={{ radio: { id: 'T' } }}>
                  <Select
                     color="red"
                     name="radio"
                     options={[
                        { value: { id: 'M' }, name: 'Male' },
                        { value: { id: 'F' }, name: 'Female' },
                        { value: { id: 'D' }, name: 'Disabled', disabled: true },
                     ]}
                  />
               </Form>
            </>
         );
      }

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

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

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

         useEffect(() => {
            formRef.current.setFieldValue('radio', { id: 'F' });
         }, []);

         return (
            <Form onSubmit={() => {}} initialData={{ radio: { id: 2 } }} ref={formRef}>
               <Select
                  name="radio"
                  options={[
                     { value: { id: 'M' }, name: 'Male' },
                     { value: { id: 'F' }, name: 'Female' },
                     { value: { id: 'D' }, name: 'Disabled', disabled: true },
                  ]}
               />
            </Form>
         );
      }

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

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

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

         useEffect(() => {
            formRef.current.setFieldError('radio', 'Field is required');
         }, []);

         return (
            <Form onSubmit={() => {}} initialData={{ radio: { id: 2 } }} ref={formRef}>
               <Select
                  name="radio"
                  options={[
                     { value: { id: 'M' }, name: 'Male' },
                     { value: { id: 'F' }, name: 'Female' },
                     { value: { id: 'D' }, name: 'Disabled', disabled: true },
                  ]}
               />
            </Form>
         );
      }

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

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

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

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

         useEffect(() => {
            formRef.current.setFieldError('checkbox', 'Field is required');
         }, []);

         return (
            <Form onSubmit={() => {}} initialData={{ checkbox: { id: 2 } }} ref={formRef}>
               <Select
                  name="radio"
                  options={[
                     { value: { id: 'M' }, name: 'Male' },
                     { value: { id: 'F' }, name: 'Female', disabled: true },
                     { value: { id: 'D' }, name: 'Disabled', disabled: true },
                  ]}
               />
            </Form>
         );
      }

      const { container } = render(<Component />);
      expect(container.firstChild).toMatchSnapshot();
   });

   it('check onChange', async () => {
      const onChange = jest.fn();

      function Component(): any {
         const [value, setValue] = useState();

         return (
            <>
               <Select
                  value={value}
                  onChange={(v: any) => {
                     onChange(v);
                     setValue(v);
                  }}
                  options={[
                     { value: { id: 'M' }, name: 'Male' },
                     { value: { id: 'F' }, name: 'Female', disabled: true },
                     { value: { id: 'D' }, name: 'Disabled', disabled: true },
                  ]}
                  data-testid="select"
               />
            </>
         );
      }

      render(<Component />);

      await fireEvent.change(screen.getByTestId('select'), { target: { value: '{"id":"M"}' } });
      await fireEvent.change(screen.getByTestId('select'), { target: { value: '{"id":"F"}' } });

      expect(onChange).toHaveBeenCalled();
      expect(onChange).toHaveBeenCalledWith({ id: 'M' });
      expect(onChange).toHaveBeenCalledWith({ id: 'F' });
   });

   it('unform - get value on onSubmit - initial value object', () => {
      const onSubmit = jest.fn();

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

         return (
            <>
               <Form onSubmit={(v) => onSubmit(v)} initialData={{ radio: { id: 'M' } }} ref={formRef}>
                  <Select
                     color="red"
                     name="radio"
                     options={[
                        { value: { id: 'M' }, name: 'Male' },
                        { value: { id: 'F' }, name: 'Female' },
                        { value: { id: 'D' }, name: 'Disabled', disabled: true },
                     ]}
                  />
                  <button
                     data-testid="submit"
                     title="submit"
                     onClick={() => {
                        formRef.current.submitForm();
                     }}
                  />
               </Form>
            </>
         );
      }

      render(<Component />);

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

      expect(onSubmit).toHaveBeenCalled();
      expect(onSubmit).toHaveBeenCalledWith({
         radio: { id: 'M' },
      });
   });

   it('unform - get value on onSubmit - initial value default', () => {
      const onSubmit = jest.fn();

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

         return (
            <>
               <Form onSubmit={(v) => onSubmit(v)} initialData={{ radio: 'M' }} ref={formRef}>
                  <Select
                     color="red"
                     name="radio"
                     options={[
                        { value: 'M', name: 'Male' },
                        { value: 'F', name: 'Female' },
                        { value: 'D', name: 'Disabled', disabled: true },
                     ]}
                  />
                  <button
                     data-testid="submit"
                     title="submit"
                     onClick={() => {
                        formRef.current.submitForm();
                     }}
                  />
               </Form>
            </>
         );
      }

      render(<Component />);

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

      expect(onSubmit).toHaveBeenCalled();
      expect(onSubmit).toHaveBeenCalledWith({
         radio: 'M',
      });
   });

   it('unform - get value on onSubmit - clear form', () => {
      const onSubmit = jest.fn();

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

         function clearForm(): void {
            formRef.current.reset();
         }

         return (
            <>
               <Form onSubmit={(v) => onSubmit(v)} initialData={{ radio: 'M' }} ref={formRef}>
                  <Select
                     color="red"
                     name="radio"
                     options={[
                        { value: 'M', name: 'Male' },
                        { value: 'F', name: 'Female' },
                        { value: 'D', name: 'Disabled', disabled: true },
                     ]}
                  />
                  <button
                     data-testid="submit"
                     title="submit"
                     onClick={() => {
                        formRef.current.submitForm();
                     }}
                  />
                  <button data-testid="clear" title="clear" onClick={clearForm} />
               </Form>
            </>
         );
      }

      render(<Component />);

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

      expect(onSubmit).toHaveBeenCalled();
      expect(onSubmit).toHaveBeenCalledWith({
         radio: null,
      });
   });

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

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

         function setData(): void {
            formRef.current.setFieldValue('radio', 'F');
         }

         return (
            <>
               <Form onSubmit={(v) => onSubmit(v)} ref={formRef}>
                  <Select
                     color="red"
                     name="radio"
                     options={[
                        { value: 'M', name: 'Male' },
                        { value: 'F', name: 'Female' },
                        { value: 'D', name: 'Disabled', disabled: true },
                     ]}
                  />
                  <button data-testid="setData" title="setData" onClick={setData} />
                  <button
                     data-testid="submit"
                     title="submit"
                     onClick={() => {
                        formRef.current.submitForm();
                     }}
                  />
               </Form>
            </>
         );
      }

      render(<Component />);

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

      expect(onSubmit).toHaveBeenCalled();
      expect(onSubmit).toHaveBeenCalledWith({
         radio: 'F',
      });
   });
});
