import { beforeEach, describe, expect, it, vi } from 'vitest'

// Mocks des composables auto-importes par Nuxt (indisponibles sous happy-dom).
const mockGet = vi.hoisted(() => vi.fn())
const mockPatch = vi.hoisted(() => vi.fn())

vi.stubGlobal('useApi', () => ({
    get: mockGet,
    post: vi.fn(),
    put: vi.fn(),
    patch: mockPatch,
    delete: vi.fn(),
}))

const { useClient } = await import('../useClient')

const SAMPLE = { '@id': '/api/clients/42', id: 42, companyName: 'ACME', isArchived: false }

describe('useClient', () => {
    beforeEach(() => {
        mockGet.mockReset()
        mockPatch.mockReset()
        mockGet.mockResolvedValue(SAMPLE)
        mockPatch.mockResolvedValue({ ...SAMPLE, isArchived: true })
    })

    it('charge le detail via GET /clients/{id} en Hydra, sans toast', async () => {
        const { client, load } = useClient(42)
        await load()

        expect(mockGet).toHaveBeenCalledWith(
            '/clients/42',
            {},
            expect.objectContaining({
                headers: { Accept: 'application/ld+json' },
                toast: false,
            }),
        )
        expect(client.value).toEqual(SAMPLE)
    })

    it('bascule loading pendant le chargement et le retombe a false', async () => {
        const { loading, load } = useClient(42)
        const promise = load()
        expect(loading.value).toBe(true)
        await promise
        expect(loading.value).toBe(false)
    })

    it('marque error et laisse client null si le GET echoue (404...)', async () => {
        mockGet.mockRejectedValueOnce(new Error('not found'))
        const { client, error, load } = useClient(99)
        await load()
        expect(error.value).toBe(true)
        expect(client.value).toBeNull()
    })

    it('archive() PATCHe { isArchived: true } sans toast puis RECHARGE le detail complet', async () => {
        // 1er GET = chargement initial, 2e GET = rechargement post-archivage.
        mockGet.mockResolvedValueOnce(SAMPLE)
        mockGet.mockResolvedValueOnce({ ...SAMPLE, isArchived: true })
        const { client, load, archive } = useClient(42)
        await load()
        await archive()

        expect(mockPatch).toHaveBeenCalledWith(
            '/clients/42',
            { isArchived: true },
            expect.objectContaining({ toast: false }),
        )
        // Le detail est re-fetch (le PATCH ne renvoie pas l'embed complet).
        expect(mockGet).toHaveBeenCalledTimes(2)
        expect(client.value?.isArchived).toBe(true)
    })

    it('restore() PATCHe { isArchived: false } (payload isArchived SEUL)', async () => {
        const { load, restore } = useClient(42)
        await load()
        await restore()

        expect(mockPatch).toHaveBeenCalledWith(
            '/clients/42',
            { isArchived: false },
            expect.objectContaining({ toast: false }),
        )
    })

    it('propage l\'erreur (ex: 409 conflit homonyme RG-1.23) au lieu de l\'avaler', async () => {
        const conflict = { response: { status: 409 } }
        mockPatch.mockRejectedValueOnce(conflict)
        const { load, restore } = useClient(42)
        await load()
        await expect(restore()).rejects.toBe(conflict)
    })
})
