import {describe, expect, test} from 'vitest'
import ApiRequestService from "~/services/data/apiRequestService";
import {$Fetch, FetchOptions} from "ohmyfetch";
import {HTTP_METHOD} from "~/types/enum/data";
import {AssociativeArray} from "~/types/data";

let fetcher: $Fetch
let apiRequestService: ApiRequestService

beforeEach(() => {
    // @ts-ignore
    fetcher = vi.fn((url: string, config: FetchOptions) => 'fetch_response') as $Fetch
    apiRequestService = new ApiRequestService(fetcher)
})

const mockedRequestMethod = (
    method: HTTP_METHOD,
    url: string,
    body: string | null = null,
    params: AssociativeArray | null = null,
    query: AssociativeArray | null = null
) => 'a_response'

describe('get', () => {
    test('simple call', async () => {
        // @ts-ignore
        apiRequestService.request = vi.fn(mockedRequestMethod)

        const result = await apiRequestService.get('https://myapi.com/api/item', { a: 1 })

        expect(result).toEqual('a_response')
        // @ts-ignore
        expect(apiRequestService.request).toHaveBeenCalledWith(
            HTTP_METHOD.GET, 'https://myapi.com/api/item', null, null, { a: 1 }
        )
    })
})

describe('post', () => {
    test('simple call', async () => {
        // @ts-ignore
        apiRequestService.request = vi.fn(mockedRequestMethod)

        const result = await apiRequestService.post(
            'https://myapi.com/api/item',
            'request_body',
            { a: 1 },
            { b: 2 },
        )

        expect(result).toEqual('a_response')
        // @ts-ignore
        expect(apiRequestService.request).toHaveBeenCalledWith(
            HTTP_METHOD.POST,
            'https://myapi.com/api/item',
            'request_body',
            { a: 1 },
            { b: 2 }
        )
    })
})

describe('put', () => {
    test('simple call', async () => {
        // @ts-ignore
        apiRequestService.request = vi.fn(mockedRequestMethod)

        const result = await apiRequestService.put(
            'https://myapi.com/api/item',
            'request_body',
            { a: 1 },
            { b: 2 },
        )

        expect(result).toEqual('a_response')
        // @ts-ignore
        expect(apiRequestService.request).toHaveBeenCalledWith(
            HTTP_METHOD.PUT,
            'https://myapi.com/api/item',
            'request_body',
            { a: 1 },
            { b: 2 }
        )
    })
})

describe('delete', () => {
    test('simple call', async () => {
        // @ts-ignore
        apiRequestService.request = vi.fn(mockedRequestMethod)

        const result = await apiRequestService.delete(
            'https://myapi.com/api/item',
            { a: 1 },
        )

        expect(result).toEqual('a_response')
        // @ts-ignore
        expect(apiRequestService.request).toHaveBeenCalledWith(
            HTTP_METHOD.DELETE,
            'https://myapi.com/api/item',
            null,
            null,
            { a: 1 },
        )
    })
})

describe('request', () => {
    test('simple call', async () => {

        // @ts-ignore
        const result = await apiRequestService.request(HTTP_METHOD.GET, 'https://myapi.com/api/item')

        expect(result).toEqual('fetch_response')
        // @ts-ignore
        expect(fetcher).toHaveBeenCalledWith('https://myapi.com/api/item', {method: 'GET'})
    })

    test('post with body', async () => {

        // @ts-ignore
        const result = await apiRequestService.request(HTTP_METHOD.POST, 'https://myapi.com/api/item', 'a_body')

        expect(result).toEqual('fetch_response')
        // @ts-ignore
        expect(fetcher).toHaveBeenCalledWith('https://myapi.com/api/item', {method: 'POST', body: 'a_body'})
    })

    test('put with body', async () => {

        // @ts-ignore
        const result = await apiRequestService.request(HTTP_METHOD.PUT, 'https://myapi.com/api/item', 'a_body')

        expect(result).toEqual('fetch_response')
        // @ts-ignore
        expect(fetcher).toHaveBeenCalledWith('https://myapi.com/api/item', {method: 'PUT', body: 'a_body'})
    })

    test('get : body must be ignored even if provided', async () => {

        // @ts-ignore
        const result = await apiRequestService.request(HTTP_METHOD.GET, 'https://myapi.com/api/item', 'a_body')

        expect(result).toEqual('fetch_response')
        // @ts-ignore
        expect(fetcher).toHaveBeenCalledWith('https://myapi.com/api/item', {method: 'GET'})
    })

    test('with query and params', async () => {
        // @ts-ignore
        const result = await apiRequestService.request(
            HTTP_METHOD.PUT,
            'https://myapi.com/api/item',
            'a_body',
            { a: 1 },
            { b: 2 }
        )

        expect(result).toEqual('fetch_response')
        // @ts-ignore
        expect(fetcher).toHaveBeenCalledWith(
            'https://myapi.com/api/item',
            {
                method: 'PUT',
                body: 'a_body',
                params: { a: 1 },
                query: { b: 2 },
            }
        )
    })
})
