import { NuxtAxiosInstance } from '@nuxtjs/axios'
import Connection from '~/services/connection/connection'
import axios from '~/plugins/Data/axios'
import { HTTP_METHOD, QUERY_TYPE } from '~/types/enums'
import { DataPersisterArgs } from '~/types/interfaces'

const axiosMock = axios as jest.Mocked<NuxtAxiosInstance>
const mockFn = jest.fn();

beforeAll(() => {
  Connection.initConnector(axiosMock)
})

describe('invoke()', () => {

  describe('getItem()', () => {
    it('should return item data', async () => {
      Connection.connector.$request = mockFn.mockReturnValue({ data: 'data user 1' })
      const response = await Connection.invoke(HTTP_METHOD.GET, 'users', { type: QUERY_TYPE.MODEL })
      expect(response).toStrictEqual({ data: 'data user 1' })
    })

    it('should call getItem', async () => {
      Connection.getItem = mockFn.mockReturnValue({})
      await Connection.invoke(HTTP_METHOD.GET, 'users', { type: QUERY_TYPE.MODEL, id: 1 })
      expect(Connection.getItem).toHaveBeenCalled()
    })
  })

  describe('getCollection() for Image type', () => {
    it('should call getCollection with a specific config', async () => {
      Connection.request = mockFn.mockReturnValue({})

      await Connection.invoke(HTTP_METHOD.GET, 'files/1/download', { showProgress: false, type: QUERY_TYPE.IMAGE })

      expect(Connection.request).toHaveBeenCalled()

      expect(Connection.request).toBeCalledWith({
          'method': HTTP_METHOD.GET,
          'progress': false,
          'responseType': 'blob',
          'url': 'files/1/download',
          'params': {}
        }
      )
    })
  })

  describe('getCollection()', () => {
    it('should return collection data', async () => {
      Connection.connector.$request = mockFn.mockReturnValue([{ data: 'data user 1' }, { data: 'data user 2' }])
      const response = await Connection.invoke(HTTP_METHOD.GET, 'users', { type: QUERY_TYPE.MODEL })
      expect(response).toStrictEqual([{ data: 'data user 1' }, { data: 'data user 2' }])
    })
    it('should call getCollection and return collection data', async () => {
      Connection.getCollection = mockFn.mockReturnValue({})
      await Connection.invoke(HTTP_METHOD.GET, 'users', { type: QUERY_TYPE.MODEL })
      expect(Connection.getCollection).toHaveBeenCalled()
    })
  })

  describe('put()', () => {
    it('should throw an error if data missing', async () => {
      expect(() => Connection.invoke(HTTP_METHOD.PUT, 'users', { type: QUERY_TYPE.MODEL })).toThrowError('*args* is not a dataPersisterArgs')
    })

    it('should return item data', async () => {
      Connection.connector.$request = mockFn.mockReturnValue({ data: 'data user 1' })
      const response = await Connection.invoke(HTTP_METHOD.PUT, 'users', { type: QUERY_TYPE.MODEL, id: 1, data: {} } as DataPersisterArgs)
      expect(response).toStrictEqual({ data: 'data user 1' })
    })

    it('should call put and return item data', async () => {
      Connection.put = mockFn.mockReturnValue({})
      await Connection.invoke(HTTP_METHOD.PUT, 'users', { type: QUERY_TYPE.MODEL, id: 1, data: {} } as DataPersisterArgs)
      expect(Connection.put).toHaveBeenCalled()
    })
  })

  describe('deleteItem()', () => {
    it('should delete item', async () => {
      Connection.connector.$request = mockFn.mockReturnValue({})
      const response = await Connection.invoke(HTTP_METHOD.DELETE, 'users', { type: QUERY_TYPE.MODEL, id: 1 })
      expect(response).toStrictEqual({})
    })

    it('should call deleteItem', async () => {
      Connection.deleteItem = mockFn.mockReturnValue({})
      await Connection.invoke(HTTP_METHOD.DELETE, 'users', { type: QUERY_TYPE.MODEL, id: 1 })
      expect(Connection.deleteItem).toHaveBeenCalled()
    })
  })
})
