import { describe, expect, it } from 'vitest'
import {
    canEditSupplier,
    categoryOptionsOf,
    contactOptionsOf,
    iriOf,
    mapAccountingDraft,
    mapAddressToDraft,
    mapAddressView,
    mapContactToDraft,
    mapRibToDraft,
    paymentTypeCodeOf,
    referentialOptionOf,
    showArchiveAction,
    showRestoreAction,
    siteOptionsOf,
    type SupplierDetail,
} from '../supplierConsultation'

describe('iriOf', () => {
    it('retourne l\'@id d\'une relation embarquee (objet)', () => {
        expect(iriOf({ '@id': '/api/payment_types/14', code: 'LCR' })).toBe('/api/payment_types/14')
    })

    it('retourne la chaine telle quelle si la relation est deja un IRI', () => {
        expect(iriOf('/api/banks/3')).toBe('/api/banks/3')
    })

    it('retourne null pour une relation absente (null / undefined / skip_null_values)', () => {
        expect(iriOf(null)).toBeNull()
        expect(iriOf(undefined)).toBeNull()
    })
})

describe('mapContactToDraft', () => {
    it('formate les telephones en XX XX XX XX XX et conserve l\'iri', () => {
        const draft = mapContactToDraft({
            '@id': '/api/supplier_contacts/39',
            id: 39,
            firstName: 'Marie',
            lastName: 'Martin',
            jobTitle: 'Responsable achats',
            phonePrimary: '0612345678',
            email: 'marie.martin@seed.test',
        })
        expect(draft.id).toBe(39)
        expect(draft.iri).toBe('/api/supplier_contacts/39')
        expect(draft.phonePrimary).toBe('06 12 34 56 78')
        expect(draft.hasSecondaryPhone).toBe(false)
    })

    it('revele le 2e telephone quand phoneSecondary est present', () => {
        const draft = mapContactToDraft({
            '@id': '/api/supplier_contacts/40',
            id: 40,
            phonePrimary: '0600000000',
            phoneSecondary: '0611111111',
        })
        expect(draft.hasSecondaryPhone).toBe(true)
        expect(draft.phoneSecondary).toBe('06 11 11 11 11')
    })
})

describe('mapAddressToDraft', () => {
    it('mappe l\'enum addressType, les champs fournisseur et extrait les iris', () => {
        const draft = mapAddressToDraft({
            '@id': '/api/supplier_addresses/33',
            id: 33,
            addressType: 'DEPART',
            country: 'France',
            postalCode: '86000',
            city: 'Poitiers',
            street: '12 rue des Acacias',
            bennes: 3,
            triageProvider: true,
            sites: [{ '@id': '/api/sites/87', name: 'Chatellerault', color: '#056CF2' }],
            categories: [{ '@id': '/api/categories/2279', code: 'NEGOCIANT' }],
            contacts: [{ '@id': '/api/supplier_contacts/39' }, '/api/supplier_contacts/41'],
        })
        expect(draft.addressType).toBe('DEPART')
        expect(draft.siteIris).toEqual(['/api/sites/87'])
        expect(draft.categoryIris).toEqual(['/api/categories/2279'])
        expect(draft.contactIris).toEqual(['/api/supplier_contacts/39', '/api/supplier_contacts/41'])
        // bennes (entier) → chaine pour MalioInputNumber.
        expect(draft.bennes).toBe('3')
        expect(draft.triageProvider).toBe(true)
        expect(draft.city).toBe('Poitiers')
        expect(draft.country).toBe('France')
    })

    it('tolere les champs absents (defauts : France, bennes « 0 », triage faux, type null)', () => {
        const draft = mapAddressToDraft({ '@id': '/api/supplier_addresses/9', id: 9 })
        expect(draft.addressType).toBeNull()
        expect(draft.siteIris).toEqual([])
        expect(draft.categoryIris).toEqual([])
        expect(draft.contactIris).toEqual([])
        expect(draft.country).toBe('France')
        expect(draft.bennes).toBe('0')
        expect(draft.triageProvider).toBe(false)
    })
})

describe('mapRibToDraft', () => {
    it('mappe label / bic / iban et l\'id serveur', () => {
        const draft = mapRibToDraft({ '@id': '/api/supplier_ribs/27', id: 27, label: 'Compte principal', bic: 'BNPAFRPPXXX', iban: 'FR14...' })
        expect(draft).toEqual({ id: 27, label: 'Compte principal', bic: 'BNPAFRPPXXX', iban: 'FR14...' })
    })
})

describe('mapAccountingDraft', () => {
    it('mappe les scalaires et resout les iris des referentiels embarques', () => {
        const acc = mapAccountingDraft({
            '@id': '/api/suppliers/85',
            id: 85,
            siren: '123456789',
            accountNumber: 'F0001',
            nTva: 'FR00123456789',
            tvaMode: { '@id': '/api/tva_modes/30' },
            paymentDelay: { '@id': '/api/payment_delays/11' },
            paymentType: { '@id': '/api/payment_types/14', code: 'LCR' },
            bank: { '@id': '/api/banks/3' },
        } as SupplierDetail)
        expect(acc).toEqual({
            siren: '123456789',
            accountNumber: 'F0001',
            nTva: 'FR00123456789',
            tvaModeIri: '/api/tva_modes/30',
            paymentDelayIri: '/api/payment_delays/11',
            paymentTypeIri: '/api/payment_types/14',
            bankIri: '/api/banks/3',
        })
    })

    it('renvoie des null quand les champs comptables sont absents (gating par omission, sans accounting.view)', () => {
        const acc = mapAccountingDraft({} as SupplierDetail)
        expect(acc).toEqual({
            siren: null,
            accountNumber: null,
            nTva: null,
            tvaModeIri: null,
            paymentDelayIri: null,
            paymentTypeIri: null,
            bankIri: null,
        })
    })
})

describe('options construites depuis l\'embed (role-independantes)', () => {
    it('categoryOptionsOf expose value=IRI, label=nom, code', () => {
        expect(categoryOptionsOf([{ '@id': '/api/categories/2279', name: 'Negociant', code: 'NEGOCIANT' }])).toEqual([
            { value: '/api/categories/2279', label: 'Negociant', code: 'NEGOCIANT' },
        ])
    })

    it('siteOptionsOf expose value=IRI, label=nom', () => {
        expect(siteOptionsOf([{ '@id': '/api/sites/87', name: 'Chatellerault', color: '#000' }])).toEqual([
            { value: '/api/sites/87', label: 'Chatellerault' },
        ])
    })

    it('contactOptionsOf compose le libelle (nom complet, sinon email)', () => {
        expect(contactOptionsOf([
            { '@id': '/api/supplier_contacts/1', id: 1, firstName: 'Marie', lastName: 'Martin' },
            { '@id': '/api/supplier_contacts/2', id: 2, email: 'a@b.fr' },
        ])).toEqual([
            { value: '/api/supplier_contacts/1', label: 'Marie Martin' },
            { value: '/api/supplier_contacts/2', label: 'a@b.fr' },
        ])
    })

    it('referentialOptionOf : option unique depuis l\'embed, vide pour IRI nu / absent', () => {
        expect(referentialOptionOf({ '@id': '/api/payment_types/14', label: 'LCR' })).toEqual([
            { value: '/api/payment_types/14', label: 'LCR' },
        ])
        expect(referentialOptionOf('/api/banks/3')).toEqual([])
        expect(referentialOptionOf(null)).toEqual([])
    })

    it('mapAddressView assemble brouillon + options propres a l\'adresse', () => {
        const view = mapAddressView({
            '@id': '/api/supplier_addresses/33',
            id: 33,
            addressType: 'RENDU',
            city: 'Poitiers',
            sites: [{ '@id': '/api/sites/87', name: 'Chatellerault' }],
            categories: [{ '@id': '/api/categories/2279', name: 'Negociant', code: 'NEGOCIANT' }],
        })
        expect(view.draft.id).toBe(33)
        expect(view.draft.addressType).toBe('RENDU')
        expect(view.siteOptions).toEqual([{ value: '/api/sites/87', label: 'Chatellerault' }])
        expect(view.categoryOptions).toEqual([{ value: '/api/categories/2279', label: 'Negociant', code: 'NEGOCIANT' }])
    })
})

describe('canEditSupplier', () => {
    const can = (granted: string[]) => (codes: string[]) => codes.some(c => granted.includes(c))

    it('visible pour manage', () => {
        expect(canEditSupplier(can(['commercial.suppliers.manage']))).toBe(true)
    })

    it('visible pour accounting.manage (role Compta)', () => {
        expect(canEditSupplier(can(['commercial.suppliers.accounting.manage']))).toBe(true)
    })

    it('masque sans aucune des deux permissions (role Usine)', () => {
        expect(canEditSupplier(can(['commercial.suppliers.view']))).toBe(false)
    })
})

describe('showArchiveAction / showRestoreAction', () => {
    const can = (granted: string[]) => (code: string) => granted.includes(code)

    it('Archiver : visible avec la permission archive ET fournisseur non archive', () => {
        expect(showArchiveAction(can(['commercial.suppliers.archive']), false)).toBe(true)
        expect(showArchiveAction(can(['commercial.suppliers.archive']), true)).toBe(false)
        expect(showArchiveAction(can([]), false)).toBe(false)
    })

    it('Restaurer : visible avec la permission archive ET fournisseur archive', () => {
        expect(showRestoreAction(can(['commercial.suppliers.archive']), true)).toBe(true)
        expect(showRestoreAction(can(['commercial.suppliers.archive']), false)).toBe(false)
        expect(showRestoreAction(can([]), true)).toBe(false)
    })
})

describe('paymentTypeCodeOf (ERP-121 : RIB masques hors-LCR en consultation)', () => {
    it('retourne le code metier quand le type de reglement est embarque', () => {
        expect(paymentTypeCodeOf({ '@id': '/api/payment_types/1', code: 'LCR' })).toBe('LCR')
        expect(paymentTypeCodeOf({ '@id': '/api/payment_types/2', code: 'VIREMENT' })).toBe('VIREMENT')
    })

    it('retourne null pour un IRI nu, un objet sans code, ou une relation absente', () => {
        expect(paymentTypeCodeOf('/api/payment_types/1')).toBeNull()
        expect(paymentTypeCodeOf({ '@id': '/api/payment_types/1' })).toBeNull()
        expect(paymentTypeCodeOf(null)).toBeNull()
        expect(paymentTypeCodeOf(undefined)).toBeNull()
    })
})
