import axios from 'axios';
import dayjs from 'dayjs';
import sinon from 'sinon';

import { DATE_FORMAT, DATE_TIME_FORMAT } from '@/shared/composables/date-format';
import { Disponibilita } from '@/shared/model/disponibilita.model';

import DisponibilitaService from './disponibilita.service';

const error = {
  response: {
    status: null,
    data: {
      type: null,
    },
  },
};

const axiosStub = {
  get: sinon.stub(axios, 'get'),
  post: sinon.stub(axios, 'post'),
  put: sinon.stub(axios, 'put'),
  patch: sinon.stub(axios, 'patch'),
  delete: sinon.stub(axios, 'delete'),
};

describe('Service Tests', () => {
  describe('Disponibilita Service', () => {
    let service: DisponibilitaService;
    let elemDefault;
    let currentDate: Date;

    beforeEach(() => {
      service = new DisponibilitaService();
      currentDate = new Date();
      elemDefault = new Disponibilita(123, 'LUNEDI', currentDate, currentDate, currentDate, 'AAAAAAA', 'AAAAAAA', 'DISPONIBILE', 'AAAAAAA');
    });

    describe('Service methods', () => {
      it('should find an element', async () => {
        const returnedFromService = {
          dataSpecifica: dayjs(currentDate).format(DATE_FORMAT),
          oraInizio: dayjs(currentDate).format(DATE_TIME_FORMAT),
          oraFine: dayjs(currentDate).format(DATE_TIME_FORMAT),
          ...elemDefault,
        };
        axiosStub.get.resolves({ data: returnedFromService });

        return service.find(123).then(res => {
          expect(res).toMatchObject(elemDefault);
        });
      });

      it('should not find an element', async () => {
        axiosStub.get.rejects(error);
        return service
          .find(123)
          .then()
          .catch(err => {
            expect(err).toMatchObject(error);
          });
      });

      it('should create a Disponibilita', async () => {
        const returnedFromService = {
          id: 123,
          dataSpecifica: dayjs(currentDate).format(DATE_FORMAT),
          oraInizio: dayjs(currentDate).format(DATE_TIME_FORMAT),
          oraFine: dayjs(currentDate).format(DATE_TIME_FORMAT),
          ...elemDefault,
        };
        const expected = { dataSpecifica: currentDate, oraInizio: currentDate, oraFine: currentDate, ...returnedFromService };

        axiosStub.post.resolves({ data: returnedFromService });
        return service.create({}).then(res => {
          expect(res).toMatchObject(expected);
        });
      });

      it('should not create a Disponibilita', async () => {
        axiosStub.post.rejects(error);

        return service
          .create({})
          .then()
          .catch(err => {
            expect(err).toMatchObject(error);
          });
      });

      it('should update a Disponibilita', async () => {
        const returnedFromService = {
          giornoSettimana: 'BBBBBB',
          dataSpecifica: dayjs(currentDate).format(DATE_FORMAT),
          oraInizio: dayjs(currentDate).format(DATE_TIME_FORMAT),
          oraFine: dayjs(currentDate).format(DATE_TIME_FORMAT),
          orarioInizio: 'BBBBBB',
          orarioFine: 'BBBBBB',
          tipo: 'BBBBBB',
          note: 'BBBBBB',
          ...elemDefault,
        };

        const expected = { dataSpecifica: currentDate, oraInizio: currentDate, oraFine: currentDate, ...returnedFromService };
        axiosStub.put.resolves({ data: returnedFromService });

        return service.update(expected).then(res => {
          expect(res).toMatchObject(expected);
        });
      });

      it('should not update a Disponibilita', async () => {
        axiosStub.put.rejects(error);

        return service
          .update({})
          .then()
          .catch(err => {
            expect(err).toMatchObject(error);
          });
      });

      it('should partial update a Disponibilita', async () => {
        const patchObject = {
          giornoSettimana: 'BBBBBB',
          dataSpecifica: dayjs(currentDate).format(DATE_FORMAT),
          oraInizio: dayjs(currentDate).format(DATE_TIME_FORMAT),
          orarioInizio: 'BBBBBB',
          tipo: 'BBBBBB',
          ...new Disponibilita(),
        };
        const returnedFromService = Object.assign(patchObject, elemDefault);

        const expected = { dataSpecifica: currentDate, oraInizio: currentDate, oraFine: currentDate, ...returnedFromService };
        axiosStub.patch.resolves({ data: returnedFromService });

        return service.partialUpdate(patchObject).then(res => {
          expect(res).toMatchObject(expected);
        });
      });

      it('should not partial update a Disponibilita', async () => {
        axiosStub.patch.rejects(error);

        return service
          .partialUpdate({})
          .then()
          .catch(err => {
            expect(err).toMatchObject(error);
          });
      });

      it('should return a list of Disponibilita', async () => {
        const returnedFromService = {
          giornoSettimana: 'BBBBBB',
          dataSpecifica: dayjs(currentDate).format(DATE_FORMAT),
          oraInizio: dayjs(currentDate).format(DATE_TIME_FORMAT),
          oraFine: dayjs(currentDate).format(DATE_TIME_FORMAT),
          orarioInizio: 'BBBBBB',
          orarioFine: 'BBBBBB',
          tipo: 'BBBBBB',
          note: 'BBBBBB',
          ...elemDefault,
        };
        const expected = { dataSpecifica: currentDate, oraInizio: currentDate, oraFine: currentDate, ...returnedFromService };
        axiosStub.get.resolves([returnedFromService]);
        return service.retrieve({ sort: {}, page: 0, size: 10 }).then(res => {
          expect(res).toContainEqual(expected);
        });
      });

      it('should not return a list of Disponibilita', async () => {
        axiosStub.get.rejects(error);

        return service
          .retrieve()
          .then()
          .catch(err => {
            expect(err).toMatchObject(error);
          });
      });

      it('should delete a Disponibilita', async () => {
        axiosStub.delete.resolves({ ok: true });
        return service.delete(123).then(res => {
          expect(res.ok).toBeTruthy();
        });
      });

      it('should not delete a Disponibilita', async () => {
        axiosStub.delete.rejects(error);

        return service
          .delete(123)
          .then()
          .catch(err => {
            expect(err).toMatchObject(error);
          });
      });
    });
  });
});
