import { describe, it, expect, vi } from 'vitest'
import { useFormErrors } from '~/shared/composables/useFormErrors'
import { useClientFormErrors } from '../useClientFormErrors'

// useFormErrors (auto-import) expose l'implementation reelle ; elle consomme
// useToast + useI18n, stubbes ici.
vi.stubGlobal('useToast', () => ({ error: vi.fn(), success: vi.fn() }))
vi.stubGlobal('useI18n', () => ({ t: (key: string) => key }))
vi.stubGlobal('useFormErrors', useFormErrors)

/**
 * Tests du composable partage `useClientFormErrors` — factorisation du cablage
 * d'erreurs des ecrans client (creation/edition), suggestion de revue ERP-101.
 * `mapRowError` ne toaste plus : il retourne un booleen et chaque page garde son
 * propre fallback (toast.error en creation, showError en edition).
 */
describe('useClientFormErrors', () => {
    it('expose les 3 etats scalaires (vides) et les 3 tableaux d\'erreurs par ligne', () => {
        const f = useClientFormErrors()
        expect(f.mainErrors.errors).toEqual({})
        expect(f.informationErrors.errors).toEqual({})
        expect(f.accountingErrors.errors).toEqual({})
        expect(f.contactErrors.value).toEqual([])
        expect(f.addressErrors.value).toEqual([])
        expect(f.ribErrors.value).toEqual([])
    })

    it('mapRowError mappe une 422 sur target[index] et retourne true', () => {
        const f = useClientFormErrors()
        const error = {
            response: {
                status: 422,
                _data: { violations: [{ propertyPath: 'email', message: 'Adresse invalide.' }] },
            },
        }
        const mapped = f.mapRowError(error, f.contactErrors, 0)
        expect(mapped).toBe(true)
        expect(f.contactErrors.value[0]).toEqual({ email: 'Adresse invalide.' })
    })

    it('mapRowError retourne false et ne touche pas la cible pour une erreur non-422', () => {
        const f = useClientFormErrors()
        const error = { response: { status: 500, _data: {} } }
        expect(f.mapRowError(error, f.ribErrors, 0)).toBe(false)
        expect(f.ribErrors.value[0]).toBeUndefined()
    })

    it('mapRowError retourne false pour une 422 sans violation exploitable', () => {
        const f = useClientFormErrors()
        const error = { response: { status: 422, _data: { 'hydra:description': 'Donnees invalides.' } } }
        expect(f.mapRowError(error, f.addressErrors, 0)).toBe(false)
        expect(f.addressErrors.value[0]).toBeUndefined()
    })
})

// Construit une erreur facon useApi : 422 avec violations Hydra.
function http422(path: string, message: string) {
    return { response: { status: 422, _data: { violations: [{ propertyPath: path, message }] } } }
}

/**
 * `submitRows` factorise la soumission d'une collection de blocs (contacts /
 * adresses / RIB) : on tente TOUS les blocs et on collecte les erreurs par index
 * sans stopper au premier echec (ERP-110 / ERP-101).
 */
describe('useClientFormErrors.submitRows', () => {
    it('tente TOUS les blocs et mappe les erreurs par index, sans stopper au premier echec', async () => {
        const { contactErrors, submitRows } = useClientFormErrors()
        const seen: number[] = []
        const onUnmapped = vi.fn()

        const saveRow = async (_row: unknown, index: number) => {
            seen.push(index)
            if (index === 1) throw http422('email', 'Email invalide')
        }

        const hasError = await submitRows(
            [{ a: 0 }, { a: 1 }, { a: 2 }],
            contactErrors,
            saveRow,
            onUnmapped,
        )

        expect(seen).toEqual([0, 1, 2]) // tous les blocs tentes
        expect(hasError).toBe(true)
        expect(contactErrors.value[1]).toEqual({ email: 'Email invalide' })
        expect(contactErrors.value[0]).toBeUndefined()
        expect(onUnmapped).not.toHaveBeenCalled() // 422 mappee, pas de fallback
    })

    it('delegue le fallback onUnmappedError pour une erreur non mappable et marque hasError', async () => {
        const { ribErrors, submitRows } = useClientFormErrors()
        const onUnmapped = vi.fn()

        const hasError = await submitRows(
            [{ a: 0 }],
            ribErrors,
            async () => { throw { response: { status: 500, _data: {} } } },
            onUnmapped,
        )

        expect(hasError).toBe(true)
        expect(onUnmapped).toHaveBeenCalledTimes(1)
        expect(ribErrors.value[0]).toBeUndefined()
    })

    it('saute les lignes filtrees par shouldSkip et renvoie false si tout passe', async () => {
        const { contactErrors, submitRows } = useClientFormErrors()
        const saved: number[] = []

        const hasError = await submitRows(
            [{ skip: true }, { skip: false }],
            contactErrors,
            async (_row, index) => { saved.push(index) },
            vi.fn(),
            (row: { skip: boolean }) => row.skip,
        )

        expect(saved).toEqual([1])
        expect(hasError).toBe(false)
    })
})
