import { describe, test, it, expect } from 'vitest'
import {AnyJson, ApiResponse, HydraMetadata} from "~/types/data";
import HydraDenormalizer from "~/services/data/normalizer/hydraDenormalizer";
import {METADATA_TYPE} from "~/types/enum/data";

describe('denormalize', () => {

    test('should parse a API Item response and return a JSON Object', () => {
        const data: AnyJson = {
            '@context': '/api/contexts/Access',
            '@id': '/api/accesses/7351',
            '@type': 'Access',
            organization: '/api/organizations/37306',
            id: 7351,
            person: {
                '@type': 'Person',
                id: 11344,
                name: 'BRUEL',
                givenName: 'Patrick'
            }
        }

        const result = HydraDenormalizer.denormalize(data)

        // @ts-ignore
        expect(result.data).toEqual(HydraDenormalizer.getData(data))
        // @ts-ignore
        expect(result.metadata).toEqual(HydraDenormalizer.getMetadata(data))

        const expected = {
            "data": {
                "@context": "/api/contexts/Access",
                "@id": "/api/accesses/7351",
                "@type": "Access",
                "id": 7351,
                "organization": "/api/organizations/37306",
                "person": {
                    "@type": "Person",
                    "givenName": "Patrick",
                    "id": 11344,
                    "name": "BRUEL"
                }
            },
            "metadata": {
                "type": METADATA_TYPE.ITEM
            }
        }

        expect(result).toStrictEqual<AnyJson>(expected)
    })

    it('should parse a API Collection response and return a JSON Object', () => {
        const data: AnyJson = {
            '@context': '/api/contexts/Access',
            '@id': '/api/accesses',
            '@type': 'hydra:Collection',
            'hydra:member': [{
                '@id': '/api/accesses/7351',
                organization: '/api/organizations/37306',
                id: 7351,
                person: {
                    '@type': 'Person',
                    id: 11344,
                    name: 'BRUEL',
                    givenName: 'Patrick'
                }
            }, {
                '@id': '/api/accesses/7352',
                organization: '/api/organizations/37306',
                id: 7352,
                person: {
                    '@type': 'Person',
                    id: 11345,
                    name: 'BRASSENS',
                    givenName: 'George'
                }
            }
            ],
            "hydra:view": {
                "@id": "/api/accesses?page=3",
                "@type": "hydra:PartialCollectionView",
                "hydra:first": "/api/accesses?page=1",
                "hydra:last": "/api/accesses?page=5",
                "hydra:next": "/api/accesses?page=4",
                "hydra:previous": "/api/accesses?page=2"
            }
        }

        const result = HydraDenormalizer.denormalize(data)

        // @ts-ignore
        expect(result.data).toEqual(HydraDenormalizer.getData(data))
        // @ts-ignore
        expect(result.metadata).toEqual(HydraDenormalizer.getMetadata(data))

        const expected = JSON.stringify(
            {"data":[
                {
                    '@id': '/api/accesses/7351',
                    organization: '/api/organizations/37306',
                    id: 7351,
                    person:
                        {
                            '@type': 'Person',
                            id: 11344,
                            name: 'BRUEL',
                            givenName: 'Patrick'
                        }
                },
                {
                    '@id': '/api/accesses/7352',
                    organization: '/api/organizations/37306',
                    id: 7352,
                    person:
                        {
                            '@type': 'Person',
                            id: 11345,
                            name: 'BRASSENS',
                            givenName: 'George'
                        }
                }
            ],
            'metadata': {
                'firstPage': 1,
                'lastPage': 5,
                'nextPage': 4,
                'previousPage': 2,
                'type': 1
            }
        })

        expect(JSON.stringify(result)).toEqual(expected)
    })
})

describe('getData', () => {
    test('With collection', () => {
        const data = {
            "@context": "/api/contexts/Foo",
            "@id": "/api/foo",
            "@type": "hydra:Collection",
            "hydra:member": [ 'foo' ],
        }

        // @ts-ignore
        expect(HydraDenormalizer.getData(data)).toEqual([ 'foo' ])
    })

    test('With item', () => {
        const data = {
            "@context": "/api/contexts/Foo",
            "@id": "/api/foo",
            "@type": "Foo",
            "param1": 'a',
        }

        // @ts-ignore
        expect(HydraDenormalizer.getData(data)).toEqual(data)
    })
})

describe('getMetadata', () => {
    test('With valid collection metadata', () => {
        const data = {
            "@context": "/api/contexts/Foo",
            "@id": "/api/foo",
            "@type": "hydra:Collection",
            "hydra:member": [ 'foo' ],
            "hydra:totalItems": 10,
            "hydra:view": {
                "@id": "/api/foo?page=3",
                "@type": "hydra:PartialCollectionView",
                "hydra:first": "/api/foo?page=1",
                "hydra:last": "/api/foo?page=5",
                "hydra:next": "/api/foo?page=4",
                "hydra:previous": "/api/foo?page=2"
            }
        }

        // @ts-ignore
        const metadata = HydraDenormalizer.getMetadata(data)

        expect(metadata.totalItems).toEqual(10)
        expect(metadata.firstPage).toEqual(1)
        expect(metadata.lastPage).toEqual(5)
        expect(metadata.nextPage).toEqual(4)
        expect(metadata.previousPage).toEqual(2)
        expect(metadata.type).toEqual(METADATA_TYPE.COLLECTION)
    })
    test('With partial collection metadata', () => {
        const data = {
            "@context": "/api/contexts/Foo",
            "@id": "/api/foo",
            "@type": "hydra:Collection",
            "hydra:member": [ 'foo' ],
            "hydra:totalItems": 10,
            "hydra:view": {
                "@id": "/api/foo?page=3",
                "@type": "hydra:PartialCollectionView",
                "hydra:first": "/api/foo?page=1",
            }
        }

        // @ts-ignore
        const metadata = HydraDenormalizer.getMetadata(data)

        expect(metadata.totalItems).toEqual(10)
        expect(metadata.firstPage).toEqual(1)
        expect(metadata.lastPage).toEqual(1)
        expect(metadata.nextPage).toEqual(undefined)
        expect(metadata.previousPage).toEqual(undefined)
    })

    test('With item metadata', () => {
        // @ts-ignore
        const metadata = HydraDenormalizer.getMetadata({})
        expect(metadata.type).toEqual(METADATA_TYPE.ITEM)
    })
})
