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 * as dateFns from 'date-fns';
import { Datepicker, IInputDatePicker } from '.';
import 'jest-styled-components';
import { Calendar, convertStringToDate } from '../../../services';
import { format, parse } from 'date-fns';

it('snapshot - padrão', () => {
   function Component(): any {
      return (
         <Form onSubmit={() => {}}>
            <Datepicker name="datepicker" />
         </Form>
      );
   }

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

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

it('snapshot - input apenas datepicker', () => {
   function Component(): any {
      return (
         <Form onSubmit={() => {}} initialData={{ datepicker: '20201212' }}>
            <Datepicker name="datepicker" />
         </Form>
      );
   }

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

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

it('snapshot - input datepicker e timepicker', () => {
   function Component(): any {
      return (
         <Form
            onSubmit={() => {}}
            initialData={{ datepicker: { date: convertStringToDate('20140211113030') } as IInputDatePicker }}
         >
            <Datepicker name="datepicker" applyOnSelect withTimePicker />
         </Form>
      );
   }

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

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

it('snapshot - input datepicker e timepicker dia todo', () => {
   function Component(): any {
      return (
         <Form
            onSubmit={() => {}}
            initialData={{
               datepicker: { date: convertStringToDate('20140211113030'), allDay: true } as IInputDatePicker,
            }}
         >
            <Datepicker name="datepicker" applyOnSelect withTimePicker />
         </Form>
      );
   }

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

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

it('snapshot - com title', () => {
   function Component(): any {
      return (
         <Form onSubmit={() => {}}>
            <Datepicker name="datepicker" title="Datepicker" />
         </Form>
      );
   }

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

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

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

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

      return (
         <Form onSubmit={() => {}} ref={formRef}>
            <Datepicker name="datepicker" title="Datepicker" />
         </Form>
      );
   }

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

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

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

it('snapshot - popup aberto/fechado', () => {
   function Component(): any {
      return (
         <Form
            onSubmit={() => {}}
            initialData={{ datepicker: '20200202' }}
         >
            <Datepicker name="datepicker" title="Datepicker" />
         </Form>
      );
   }

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

   // Abrir popup
   fireEvent.click(screen.getByTestId('datepicker-input'));
   expect(screen.getByTestId('datepicker-popup')).not.toBeUndefined();
   expect(container.firstChild).toMatchSnapshot();

   // Fechar popup
   fireEvent.click(screen.getByTestId('20200210'));
   expect(screen.queryByTestId('datepicker-popup')).toBeNull();
   expect(container.firstChild).toMatchSnapshot();
});

it('snapshot - popup aberto/fechado com timepicker', () => {
   function Component(): any {
      return (
         <Form
            onSubmit={() => {}}
            initialData={{ datepicker: '20200202' }}
         >
            <Datepicker name="datepicker" title="Datepicker" withTimePicker />
         </Form>
      );
   }

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

   // Abrir popup
   fireEvent.click(screen.getByTestId('datepicker-input'));
   expect(screen.getByTestId('datepicker-popup')).not.toBeUndefined();
   expect(screen.getByTestId('datepicker-input-hour')).not.toBeUndefined();
   expect(screen.getByTestId('datepicker-input-minute')).not.toBeUndefined();
   expect(container.firstChild).toMatchSnapshot();

   // Fechar popup
   fireEvent.click(screen.getByTestId('20200210'));
   fireEvent.click(screen.getByTestId('datepicker-apply'));
   expect(screen.queryByTestId('datepicker-popup')).toBeNull();
   expect(screen.queryByTestId('datepicker-input-hour')).toBeNull();
   expect(screen.queryByTestId('datepicker-input-minute')).toBeNull();
   expect(container.firstChild).toMatchSnapshot();
});

it('snapshot - onChange deve remover erro', () => {
   function Component(): any {
      const formRef = useRef<FormHandles>();

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

      return (
         <Form onSubmit={() => {}} ref={formRef}>
            <Datepicker name="datepicker" title="Datepicker" />
         </Form>
      );
   }

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

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

   // Definir data
   fireEvent.click(screen.getByTestId('datepicker-input'));
   fireEvent.click(screen.getByTestId('20201210'));

   expect(screen.queryByTestId('input-error')).toBeNull();
});

it('clear - limpar input com valor inicial', () => {
   function Component(): any {
      return (
         <Form onSubmit={() => {}} initialData={{ datepicker: '19991212' }}>
            <Datepicker name="datepicker" title="Datepicker" />
         </Form>
      );
   }

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

   // Definir data
   expect(screen.queryByTestId('datepicker-input').textContent).toEqual('12 Dec 1999');

   // Limpar input
   fireEvent.click(screen.getByTestId('datepicker-remove-date'));
   expect(screen.queryByTestId('datepicker-input').textContent).toEqual('Selecione um data');
});

it('clear - limpar input com valor definido', () => {
   function Component(): any {
      return (
         <Form onSubmit={() => {}}>
            <Datepicker name="datepicker" title="Datepicker" />
         </Form>
      );
   }

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

   // Definir data
   fireEvent.click(screen.getByTestId('datepicker-input'));
   fireEvent.click(screen.getByTestId(format(new Date(), 'yyyyMMdd')));
   expect(screen.queryByTestId('datepicker-input').textContent).toEqual(format(new Date(), 'd MMM yyyy'));

   // Limpar input
   fireEvent.click(screen.getByTestId('datepicker-remove-date'));
   expect(screen.queryByTestId('datepicker-input').textContent).toEqual('Selecione um data');
});

it('clear - limpar sem nenhum valor', () => {
   function Component(): any {
      return (
         <Form onSubmit={() => {}}>
            <Datepicker name="datepicker" title="Datepicker" />
         </Form>
      );
   }

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

   // Não existe remover data
   expect(screen.queryByTestId('datepicker-remove-date')).toBeNull();
});

it('onSumit - datepicker', () => {
   const onSubmit = jest.fn();

   function Component(): any {
      return (
         <Form onSubmit={(data) => onSubmit(data)}>
            <Datepicker name="datepicker" title="Datepicker" />
            <button type="submit" data-testid="submit">
               Submit
            </button>
         </Form>
      );
   }

   render(<Component />);

   // Definir data
   fireEvent.click(screen.getByTestId('datepicker-input'));
   fireEvent.click(screen.getByTestId(format(new Date(), 'yyyyMMdd')));
   // expect(screen.queryByTestId('datepicker-input').textContent).toEqual(format(new Date(), 'd MMM yyyy'));

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

   expect(onSubmit).toHaveBeenCalled();
   expect(onSubmit).toHaveBeenCalledWith({
      datepicker: expect.objectContaining({
         date: expect.any(Date),
         day: dateFns.getDate(new Date()),
         month: dateFns.getMonth(new Date()) + 1,
         year: dateFns.getYear(new Date()),
         dateYYYYMMDD: dateFns.format(new Date(), 'yyyyMMdd'),
         dateYYYYMMDDhhiiss: dateFns.format(new Date(), 'yyyyMMddHHmm00'),
         allDay: false,
         hour: dateFns.getHours(new Date()),
         minutes: dateFns.getMinutes(new Date()),
         isToday: dateFns.isToday(new Date()),
      }),
   });
});

it('onSumit - datepicker/timepicker', () => {
   const onSubmit = jest.fn();

   function Component(): any {
      return (
         <Form onSubmit={(data) => onSubmit(data)}>
            <Datepicker name="datepicker" title="Datepicker" withTimePicker />
            <button type="submit" data-testid="submit">
               Submit
            </button>
         </Form>
      );
   }

   render(<Component />);

   // Definir data
   fireEvent.click(screen.getByTestId('datepicker-input'));
   fireEvent.click(screen.getByTestId(format(new Date(), 'yyyyMMdd')));
   fireEvent.input(screen.getByTestId('datepicker-input-hour'), { target: { value: '05' } });
   fireEvent.input(screen.getByTestId('datepicker-input-minute'), { target: { value: '10' } });
   fireEvent.click(screen.getByTestId('datepicker-apply'));

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

   expect(onSubmit).toHaveBeenCalled();
   expect(onSubmit).toHaveBeenCalledWith({
      datepicker: expect.objectContaining({
         date: expect.any(Date),
         day: dateFns.getDate(new Date()),
         month: dateFns.getMonth(new Date()) + 1,
         year: dateFns.getYear(new Date()),
         dateYYYYMMDD: dateFns.format(new Date(), 'yyyyMMdd'),
         dateYYYYMMDDhhiiss: dateFns.format(new Date(), 'yyyyMMdd051000'),
         allDay: false,
         hour: 5,
         minutes: 10,
         isToday: dateFns.isToday(new Date()),
      }),
   });
});

it('onSumit - datepicker/timepicker com dia todo', () => {
   const onSubmit = jest.fn();

   function Component(): any {
      return (
         <Form onSubmit={(data) => onSubmit(data)}>
            <Datepicker name="datepicker" title="Datepicker" withTimePicker />
            <button type="submit" data-testid="submit">
               Submit
            </button>
         </Form>
      );
   }

   render(<Component />);

   // Definir data
   fireEvent.click(screen.getByTestId('datepicker-input'));
   fireEvent.click(screen.getByTestId(format(new Date(), 'yyyyMMdd')));
   fireEvent.input(screen.getByTestId('datepicker-input-hour'), { target: { value: '05' } });
   fireEvent.input(screen.getByTestId('datepicker-input-minute'), { target: { value: '10' } });
   fireEvent.click(screen.getByTestId('datepicker-all-day'));
   fireEvent.click(screen.getByTestId('datepicker-apply'));

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

   expect(onSubmit).toHaveBeenCalled();
   expect(onSubmit).toHaveBeenCalledWith({
      datepicker: expect.objectContaining({
         date: expect.any(Date),
         day: dateFns.getDate(new Date()),
         month: dateFns.getMonth(new Date()) + 1,
         year: dateFns.getYear(new Date()),
         dateYYYYMMDD: dateFns.format(new Date(), 'yyyyMMdd'),
         dateYYYYMMDDhhiiss: dateFns.format(new Date(), 'yyyyMMdd000000'),
         allDay: true,
         hour: 0,
         minutes: 0,
         isToday: dateFns.isToday(new Date()),
      }),
   });
});

it('onSumit - valor inicial com datepicker', () => {
   const onSubmit = jest.fn();

   function Component(): any {
      return (
         <Form onSubmit={(data) => onSubmit(data)} initialData={{ datepicker: '20201212' }}>
            <Datepicker name="datepicker" title="Datepicker" />
            <button type="submit" data-testid="submit">
               Submit
            </button>
         </Form>
      );
   }

   render(<Component />);

   // Definir data
   fireEvent.click(screen.getByTestId('submit'));

   const date = convertStringToDate('20201212');
   expect(onSubmit).toHaveBeenCalled();
   expect(onSubmit).toHaveBeenCalledWith({
      datepicker: expect.objectContaining({
         date: expect.any(Date),
         day: dateFns.getDate(date),
         month: dateFns.getMonth(date) + 1,
         year: dateFns.getYear(date),
         dateYYYYMMDD: dateFns.format(date, 'yyyyMMdd'),
         dateYYYYMMDDhhiiss: dateFns.format(date, 'yyyyMMddHHmm00'),
         allDay: false,
         hour: dateFns.getHours(date),
         minutes: dateFns.getMinutes(date),
         isToday: dateFns.isToday(date),
      }),
   });
});

it('onSumit - valor inicial com datepicker/timepicker', () => {
   const onSubmit = jest.fn();

   function Component(): any {
      return (
         <Form onSubmit={(data) => onSubmit(data)} initialData={{ datepicker: '20201212' }}>
            <Datepicker name="datepicker" title="Datepicker" withTimePicker />
            <button type="submit" data-testid="submit">
               Submit
            </button>
         </Form>
      );
   }

   render(<Component />);

   // Definir data
   fireEvent.click(screen.getByTestId('submit'));

   const date = convertStringToDate('20201212');
   expect(onSubmit).toHaveBeenCalled();
   expect(onSubmit).toHaveBeenCalledWith({
      datepicker: expect.objectContaining({
         date: expect.any(Date),
         day: dateFns.getDate(date),
         month: dateFns.getMonth(date) + 1,
         year: dateFns.getYear(date),
         dateYYYYMMDD: dateFns.format(date, 'yyyyMMdd'),
         dateYYYYMMDDhhiiss: dateFns.format(date, 'yyyyMMddHHmm00'),
         allDay: false,
         hour: dateFns.getHours(date),
         minutes: dateFns.getMinutes(date),
         isToday: dateFns.isToday(date),
      }),
   });
});

it('onSumit - valor inicial com datepicker com dia todo', () => {
   const onSubmit = jest.fn();

   function Component(): any {
      return (
         <Form
            onSubmit={(data) => onSubmit(data)}
            initialData={{
               datepicker: { date: convertStringToDate('20140211113000'), allDay: true } as IInputDatePicker,
            }}
         >
            <Datepicker name="datepicker" title="Datepicker" withTimePicker />
            <button type="submit" data-testid="submit">
               Submit
            </button>
         </Form>
      );
   }

   render(<Component />);

   // Definir data
   fireEvent.click(screen.getByTestId('submit'));

   const date = convertStringToDate('20140211113000');
   expect(onSubmit).toHaveBeenCalled();
   expect(onSubmit).toHaveBeenCalledWith({
      datepicker: expect.objectContaining({
         date: expect.any(Date),
         day: dateFns.getDate(date),
         month: dateFns.getMonth(date) + 1,
         year: dateFns.getYear(date),
         dateYYYYMMDD: dateFns.format(date, 'yyyyMMdd'),
         dateYYYYMMDDhhiiss: dateFns.format(date, 'yyyyMMdd000000'),
         allDay: true,
         hour: 0,
         minutes: 0,
         isToday: dateFns.isToday(date),
      }),
   });
});

it("popup com 'dia todo' selecionado deve esconder hora", () => {
   function Component(): any {
      return (
         <Form onSubmit={() => {}} initialData={{ datepicker: '20201212' }}>
            <Datepicker name="datepicker" title="Datepicker" withTimePicker />
         </Form>
      );
   }

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

   // Abrir popup
   fireEvent.click(screen.getByTestId('datepicker-input'));
   expect(screen.getByTestId('datepicker-popup')).not.toBeUndefined();
   expect(screen.getByTestId('datepicker-input-hour')).not.toBeUndefined();
   expect(screen.getByTestId('datepicker-input-minute')).not.toBeUndefined();
   // Dia todo
   fireEvent.click(screen.getByTestId('datepicker-all-day'));
   expect(screen.queryByTestId('datepicker-input-hour')).toBeNull();
   expect(screen.queryByTestId('datepicker-input-minute')).toBeNull();
});

it('avançar mês', () => {
   function Component(): any {
      return (
         <Form onSubmit={() => {}} initialData={{ datepicker: '20201212' }}>
            <Datepicker name="datepicker" title="Datepicker" withTimePicker />
         </Form>
      );
   }

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

   // Abrir popup
   fireEvent.click(screen.getByTestId('datepicker-input'));
   expect(screen.getByTestId('datepicker-popup')).not.toBeUndefined();
   expect(screen.queryByTestId('datepicker-month-name').textContent).toEqual('Dezembro, 2020');

   // Avançar mês
   fireEvent.click(screen.getByTestId('datepicker-next-month'));
   expect(screen.queryByTestId('datepicker-month-name').textContent).toEqual('Janeiro, 2021');
});

it('voltar mês', () => {
   function Component(): any {
      return (
         <Form onSubmit={() => {}} initialData={{ datepicker: '20201212' }}>
            <Datepicker name="datepicker" title="Datepicker" withTimePicker />
         </Form>
      );
   }

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

   // Abrir popup
   fireEvent.click(screen.getByTestId('datepicker-input'));
   expect(screen.getByTestId('datepicker-popup')).not.toBeUndefined();
   expect(screen.queryByTestId('datepicker-month-name').textContent).toEqual('Dezembro, 2020');

   // Avançar mês
   fireEvent.click(screen.getByTestId('datepicker-previous-month'));
   expect(screen.queryByTestId('datepicker-month-name').textContent).toEqual('Novembro, 2020');
});

it('definir data com applyOnSelect = false', () => {
   function Component(): any {
      return (
         <Form onSubmit={() => {}}>
            <Datepicker name="datepicker" title="Datepicker" />
         </Form>
      );
   }

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

   // Definir data
   fireEvent.click(screen.getByTestId('datepicker-input'));
   fireEvent.click(screen.getByTestId(format(new Date(), 'yyyyMMdd')));
   expect(screen.queryByTestId('datepicker-input').textContent).toEqual(format(new Date(), 'd MMM yyyy'));

   // Limpar input
   fireEvent.click(screen.getByTestId('datepicker-remove-date'));
   expect(screen.queryByTestId('datepicker-input').textContent).toEqual('Selecione um data');
});

it('definir data com applyOnSelect = true', () => {
   function Component(): any {
      return (
         <Form onSubmit={() => {}}>
            <Datepicker name="datepicker" title="Datepicker" applyOnSelect />
         </Form>
      );
   }

   render(<Component />);

   // Definir data
   fireEvent.click(screen.getByTestId('datepicker-input'));
   fireEvent.click(screen.getByTestId(format(new Date(), 'yyyyMMdd')));
   expect(screen.queryByTestId('datepicker-input').textContent).toEqual('Selecione um data');

   // Aplicar
   fireEvent.click(screen.getByTestId('datepicker-apply'));
   expect(screen.queryByTestId('datepicker-input').textContent).toEqual(format(new Date(), 'd MMM yyyy'));
});

it('selecionar data com applyOnSelect=true e cancelar, deve voltar valor original', () => {
   function Component(): any {
      return (
         <Form onSubmit={() => {}} initialData={{ datepicker: '19991212' }}>
            <Datepicker name="datepicker" title="Datepicker" applyOnSelect />
         </Form>
      );
   }

   render(<Component />);

   // Definir data
   expect(screen.queryByTestId('datepicker-input').textContent).toEqual('12 Dec 1999');

   // Verificar se data definida esta selecionada
   fireEvent.click(screen.getByTestId('datepicker-input'));
   expect(screen.getByTestId('19991212').className).toContain('select');
   // Clicar em outra data
   fireEvent.click(screen.getByTestId('19991210'));
   expect(screen.getByTestId('19991210').className).toContain('select');
   // Clicar em outra data
   fireEvent.click(screen.getByTestId('19991224'));
   expect(screen.getByTestId('19991224').className).toContain('select');
   // Cancelar
   fireEvent.click(screen.getByTestId('datepicker-cancel'));

   // Verificar se data definida esta selecionada
   fireEvent.click(screen.getByTestId('datepicker-input'));
   expect(screen.getByTestId('19991212').className).toContain('select');
});

it('avançar mês e depois cancelar, deve voltar para mês/ano da data selecionado', () => {
   function Component(): any {
      return (
         <Form onSubmit={() => {}} initialData={{ datepicker: '19991212' }}>
            <Datepicker name="datepicker" title="Datepicker" applyOnSelect />
         </Form>
      );
   }

   render(<Component />);

   // Definir data
   expect(screen.queryByTestId('datepicker-input').textContent).toEqual('12 Dec 1999');

   // Verificar se data definida esta selecionada
   fireEvent.click(screen.getByTestId('datepicker-input'));
   expect(screen.getByTestId('19991212').className).toContain('select');

   // Avançar mês
   fireEvent.click(screen.getByTestId('datepicker-next-month'));
   expect(screen.queryByTestId('datepicker-month-name').textContent).toEqual('Janeiro, 2000');

   // Avançar mês
   fireEvent.click(screen.getByTestId('datepicker-next-month'));
   expect(screen.queryByTestId('datepicker-month-name').textContent).toEqual('Fevereiro, 2000');

   // Cancelar
   fireEvent.click(screen.getByTestId('datepicker-cancel'));

   // Verificar se data definida esta selecionada
   fireEvent.click(screen.getByTestId('datepicker-input'));
   // deve voltar no mês da data definida
   expect(screen.queryByTestId('datepicker-month-name').textContent).toEqual('Dezembro, 1999');
   expect(screen.getByTestId('19991212').className).toContain('select');
});

it('avançar mês e depois cancelar, deve voltar para mês/ano da data atual (caso não tenha nenhuma data definida)', () => {
   function Component(): any {
      return (
         <Form onSubmit={() => {}}>
            <Datepicker name="datepicker" title="Datepicker" applyOnSelect />
         </Form>
      );
   }

   render(<Component />);

   // Definir data
   expect(screen.queryByTestId('datepicker-input').textContent).toEqual('Selecione um data');

   // Verificar se data definida esta selecionada
   fireEvent.click(screen.getByTestId('datepicker-input'));
   expect(screen.queryByTestId('datepicker-month-name').textContent).toEqual(
      `${Calendar.monthsName[new Date().getMonth()]}, ${new Date().getFullYear()}`,
   );

   // Avançar mês
   fireEvent.click(screen.getByTestId('datepicker-next-month'));
   // Avançar mês
   fireEvent.click(screen.getByTestId('datepicker-next-month'));

   // Cancelar
   fireEvent.click(screen.getByTestId('datepicker-cancel'));

   // Verificar se data definida esta selecionada
   fireEvent.click(screen.getByTestId('datepicker-input'));
   // deve voltar no mês da data definida
   expect(screen.queryByTestId('datepicker-month-name').textContent).toEqual(
      `${Calendar.monthsName[new Date().getMonth()]}, ${new Date().getFullYear()}`,
   );
});
