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

// formatPhoneFR est auto-importe dans le helper via le chemin partage ; on le mocke
// pour un rendu deterministe (la mise en forme exacte est testee ailleurs).
vi.mock('~/shared/utils/phone', () => ({
    formatPhoneFR: (v: string) => `fmt(${v})`,
}))

const {
    canEditProvider,
    categoryOptionsOf,
    contactOptionsOf,
    iriOf,
    irisOf,
    mapAccountingDraft,
    mapAddressToDraft,
    mapContactToDraft,
    mapRibToDraft,
    paymentTypeCodeOf,
    referentialOptionOf,
    showArchiveAction,
    showRestoreAction,
    siteOptionsOf,
} = await import('../providerDetail')

/**
 * Helpers purs des ecrans Consultation / Modification (ERP-145) : mapping du
 * detail embarque vers les brouillons + regles d'affichage des actions (Modifier /
 * Archiver / Restaurer).
 */
describe('providerDetail helpers', () => {
    describe('iriOf / irisOf', () => {
        it('extrait l\'IRI d\'un objet embarque, d\'un IRI nu, ou null', () => {
            expect(iriOf({ '@id': '/api/banks/2' })).toBe('/api/banks/2')
            expect(iriOf('/api/banks/2')).toBe('/api/banks/2')
            expect(iriOf(null)).toBeNull()
            expect(iriOf(undefined)).toBeNull()
        })

        it('extrait les IRI d\'une collection embarquee', () => {
            expect(irisOf([{ '@id': '/api/sites/1' }, { '@id': '/api/sites/2' }])).toEqual(['/api/sites/1', '/api/sites/2'])
            expect(irisOf(undefined)).toEqual([])
        })
    })

    describe('mapContactToDraft', () => {
        it('mappe les champs, formate les telephones et derive hasSecondaryPhone', () => {
            const draft = mapContactToDraft({
                '@id': '/api/provider_contacts/5',
                id: 5,
                firstName: 'Jean',
                lastName: 'Dupont',
                phonePrimary: '0102030405',
                phoneSecondary: '0607080910',
                email: 'jean@x.fr',
            })
            expect(draft).toMatchObject({
                id: 5,
                iri: '/api/provider_contacts/5',
                firstName: 'Jean',
                lastName: 'Dupont',
                phonePrimary: 'fmt(0102030405)',
                phoneSecondary: 'fmt(0607080910)',
                email: 'jean@x.fr',
                hasSecondaryPhone: true,
            })
        })

        it('hasSecondaryPhone faux sans 2e numero', () => {
            const draft = mapContactToDraft({ '@id': '/api/provider_contacts/6', id: 6, lastName: 'Doe' })
            expect(draft.hasSecondaryPhone).toBe(false)
            expect(draft.phoneSecondary).toBeNull()
        })
    })

    describe('mapAddressToDraft', () => {
        it('extrait les IRI des sites / categories / contacts embarques', () => {
            const draft = mapAddressToDraft({
                '@id': '/api/provider_addresses/3',
                id: 3,
                country: 'France',
                postalCode: '86100',
                city: 'Châtellerault',
                street: '1 rue du Test',
                sites: [{ '@id': '/api/sites/1' }],
                categories: [{ '@id': '/api/categories/7' }],
                contacts: [{ '@id': '/api/provider_contacts/5' }, '/api/provider_contacts/6'],
            })
            expect(draft.siteIris).toEqual(['/api/sites/1'])
            expect(draft.categoryIris).toEqual(['/api/categories/7'])
            expect(draft.contactIris).toEqual(['/api/provider_contacts/5', '/api/provider_contacts/6'])
            expect(draft.id).toBe(3)
        })
    })

    describe('mapAccountingDraft / mapRibToDraft', () => {
        it('mappe les scalaires et les IRI des referentiels embarques', () => {
            const draft = mapAccountingDraft({
                '@id': '/api/providers/9',
                id: 9,
                siren: '123456789',
                accountNumber: '4010',
                nTva: 'FR123',
                tvaMode: { '@id': '/api/tva_modes/1', label: 'TVA' },
                paymentType: { '@id': '/api/payment_types/3', code: 'VIREMENT' },
                bank: { '@id': '/api/banks/2' },
            })
            expect(draft.tvaModeIri).toBe('/api/tva_modes/1')
            expect(draft.paymentTypeIri).toBe('/api/payment_types/3')
            expect(draft.bankIri).toBe('/api/banks/2')
            expect(draft.paymentDelayIri).toBeNull()
            expect(draft.siren).toBe('123456789')
        })

        it('mappe un RIB embarque', () => {
            expect(mapRibToDraft({ '@id': '/api/provider_ribs/1', id: 1, label: 'Compte', bic: 'BIC', iban: 'IBAN' }))
                .toEqual({ id: 1, label: 'Compte', bic: 'BIC', iban: 'IBAN' })
        })
    })

    describe('options builders (libelles role-independants depuis l\'embed)', () => {
        it('categoryOptionsOf / siteOptionsOf / contactOptionsOf', () => {
            expect(categoryOptionsOf([{ '@id': '/api/categories/7', name: 'Maintenance', code: 'MAINT' }]))
                .toEqual([{ value: '/api/categories/7', label: 'Maintenance' }])
            expect(siteOptionsOf([{ '@id': '/api/sites/1', name: 'Châtellerault' }]))
                .toEqual([{ value: '/api/sites/1', label: 'Châtellerault' }])
            expect(contactOptionsOf([{ '@id': '/api/provider_contacts/5', id: 5, firstName: 'Jean', lastName: 'Dupont' }]))
                .toEqual([{ value: '/api/provider_contacts/5', label: 'Jean Dupont' }])
        })

        it('referentialOptionOf / paymentTypeCodeOf', () => {
            expect(referentialOptionOf({ '@id': '/api/banks/2', label: 'SG' }))
                .toEqual([{ value: '/api/banks/2', label: 'SG' }])
            expect(referentialOptionOf(null)).toEqual([])
            expect(referentialOptionOf('/api/banks/2')).toEqual([])
            expect(paymentTypeCodeOf({ '@id': '/api/payment_types/3', code: 'LCR' })).toBe('LCR')
            expect(paymentTypeCodeOf(null)).toBeNull()
        })
    })

    describe('actions selon permissions', () => {
        /** Fabrique un `can` qui n'autorise que les codes fournis. */
        const canFor = (granted: string[]) => (code: string) => granted.includes(code)
        const canAnyFor = (granted: string[]) => (codes: string[]) => codes.some(c => granted.includes(c))

        it('« Modifier » visible avec manage OU accounting.manage (Compta inclus)', () => {
            expect(canEditProvider(canAnyFor(['technique.providers.manage']))).toBe(true)
            expect(canEditProvider(canAnyFor(['technique.providers.accounting.manage']))).toBe(true)
            expect(canEditProvider(canAnyFor(['technique.providers.view']))).toBe(false)
        })

        it('« Archiver » visible seulement avec archive ET prestataire actif (Admin seul)', () => {
            const admin = canFor(['technique.providers.archive'])
            const bureau = canFor(['technique.providers.manage'])
            expect(showArchiveAction(admin, false)).toBe(true)
            expect(showArchiveAction(admin, true)).toBe(false) // deja archive -> Restaurer
            expect(showArchiveAction(bureau, false)).toBe(false) // pas la permission archive
        })

        it('« Restaurer » visible seulement avec archive ET prestataire archive', () => {
            const admin = canFor(['technique.providers.archive'])
            expect(showRestoreAction(admin, true)).toBe(true)
            expect(showRestoreAction(admin, false)).toBe(false)
            expect(showRestoreAction(canFor([]), true)).toBe(false)
        })
    })
})
