import { describe, it, expect } from 'vitest'
import {
    buildAccountingPayload,
    buildAddressPayload,
    buildContactPayload,
    buildInformationPayload,
    buildMainPayload,
    buildRibPayload,
    mapAccountingFormDraft,
    mapInformationDraft,
    mapMainDraft,
    resolveTabEditability,
} from '../supplierEdit'
import type { SupplierDetail } from '~/modules/commercial/utils/forms/supplierConsultation'
import { emptyAddress, emptyContact, emptyRib } from '~/modules/commercial/types/supplierForm'

describe('buildMainPayload (groupe supplier:write:main)', () => {
    it('envoie companyName + categories quand renseignes', () => {
        expect(buildMainPayload({ companyName: 'ACME', categoryIris: ['/api/categories/1'] })).toEqual({
            companyName: 'ACME',
            categories: ['/api/categories/1'],
        })
    })

    it('CREATION : omet companyName vide (-> 422 NotBlank, ERP-119)', () => {
        const payload = buildMainPayload({ companyName: null, categoryIris: [] })
        expect('companyName' in payload).toBe(false)
        expect(payload.categories).toEqual([])
    })

    it('EDITION (forUpdate) : companyName vide envoye en `\'\'` (PATCH -> 422 NotBlank, pas un faux 200)', () => {
        const payload = buildMainPayload({ companyName: '', categoryIris: [] }, { forUpdate: true })
        expect('companyName' in payload).toBe(true)
        expect(payload.companyName).toBe('')
    })
})

describe('buildInformationPayload (groupe supplier:write:information)', () => {
    const base = {
        description: null, competitors: null, foundedAt: null, foundedAtRaw: '', employeesCount: null,
        revenueAmount: null, profitAmount: null, directorName: null, volumeForecast: null,
    }

    it('convertit employeesCount et volumeForecast en nombre, null si vide', () => {
        expect(buildInformationPayload({ ...base, employeesCount: '42', volumeForecast: '1000' })).toMatchObject({
            employeesCount: 42,
            volumeForecast: 1000,
        })
        expect(buildInformationPayload(base)).toMatchObject({ employeesCount: null, volumeForecast: null })
    })

    it('envoie la saisie invalide (foundedAtRaw) en priorite -> le back tranchera (422)', () => {
        // Saisie malformee transmise telle quelle pour declencher la 422 back (MUI-44).
        expect(buildInformationPayload({ ...base, foundedAt: null, foundedAtRaw: '32/13/2026' }).foundedAt)
            .toBe('32/13/2026')
        // Saisie valide : foundedAtRaw vide -> on envoie la date ISO.
        expect(buildInformationPayload({ ...base, foundedAt: '2008-04-01', foundedAtRaw: '' }).foundedAt)
            .toBe('2008-04-01')
    })
})

describe('buildContactPayload (sous-ressource supplier_contact)', () => {
    it('n\'envoie le 2e telephone que si revele (hasSecondaryPhone)', () => {
        const contact = { ...emptyContact(), phonePrimary: '0102030405', phoneSecondary: '0607080910' }
        expect(buildContactPayload({ ...contact, hasSecondaryPhone: false }).phoneSecondary).toBeNull()
        expect(buildContactPayload({ ...contact, hasSecondaryPhone: true }).phoneSecondary).toBe('0607080910')
    })
})

describe('buildAddressPayload (sous-ressource supplier_address — specificites M2)', () => {
    it('envoie addressType (enum), bennes (nombre) et triageProvider', () => {
        const address = {
            ...emptyAddress(),
            addressType: 'RENDU' as const,
            postalCode: '86100', city: 'Châtellerault', street: '1 rue de la Paix',
            siteIris: ['/api/sites/1'], categoryIris: ['/api/categories/2'],
            bennes: '3', triageProvider: true,
        }
        expect(buildAddressPayload(address)).toMatchObject({
            addressType: 'RENDU',
            bennes: 3,
            triageProvider: true,
            sites: ['/api/sites/1'],
            categories: ['/api/categories/2'],
        })
    })

    it('bennes null quand le champ est vide', () => {
        expect(buildAddressPayload({ ...emptyAddress(), bennes: '' }).bennes).toBeNull()
    })

    it('omet postalCode / city / street vides (-> 422 NotBlank, ERP-119)', () => {
        const payload = buildAddressPayload({ ...emptyAddress(), addressType: 'PROSPECT' })
        expect('postalCode' in payload).toBe(false)
        expect('city' in payload).toBe(false)
        expect('street' in payload).toBe(false)
        // Les champs non requis restent presents.
        expect('streetComplement' in payload).toBe(true)
        expect(payload.addressType).toBe('PROSPECT')
    })

    it('omet addressType quand aucun radio n\'est choisi (-> 422 NotBlank au lieu d\'un 400 de type)', () => {
        // emptyAddress() laisse addressType a null : la cle doit etre absente du
        // payload pour que le back renvoie une 422 propertyPath addressType.
        const payload = buildAddressPayload(emptyAddress())
        expect('addressType' in payload).toBe(false)
    })

    it('EDITION (forUpdate) : un champ requis vide est envoye en `\'\'` (et NON omis) pour declencher la 422 NotBlank au PATCH', () => {
        // Bug edition : omettre la cle d'un champ requis vide laisse le PATCH garder
        // l'ancienne valeur (faux 200). En `forUpdate`, on envoie `''` -> NotBlank 422.
        const payload = buildAddressPayload({ ...emptyAddress(), addressType: 'DEPART', postalCode: '' }, { forUpdate: true })
        expect('postalCode' in payload).toBe(true)
        expect(payload.postalCode).toBe('')
        // Un champ requis renseigne reste tel quel.
        expect(payload.addressType).toBe('DEPART')
    })

    it('n\'expose jamais d\'email de facturation (difference M1)', () => {
        const payload = buildAddressPayload({ ...emptyAddress(), addressType: 'DEPART' })
        expect('billingEmail' in payload).toBe(false)
    })
})

describe('buildAccountingPayload (groupe supplier:write:accounting)', () => {
    const base = {
        siren: '123456789', accountNumber: '00012345678', nTva: 'FR123',
        tvaModeIri: '/api/tva_modes/1', paymentDelayIri: '/api/payment_delays/1',
        paymentTypeIri: '/api/payment_types/1', bankIri: '/api/banks/1',
    }

    it('envoie la banque seulement si requise (VIREMENT, RG-2.07)', () => {
        expect(buildAccountingPayload(base, true).bank).toBe('/api/banks/1')
        expect(buildAccountingPayload(base, false).bank).toBeNull()
    })
})

describe('buildRibPayload (sous-ressource supplier_rib)', () => {
    it('omet les champs requis vides (-> 422 NotBlank, ERP-119)', () => {
        const payload = buildRibPayload({ ...emptyRib(), iban: 'FR1420041010050500013M02606' })
        expect('label' in payload).toBe(false)
        expect('bic' in payload).toBe(false)
        expect(payload.iban).toBe('FR1420041010050500013M02606')
    })
})

describe('mapMainDraft — pre-remplissage bloc principal (companyName + categories, pas de relation M2)', () => {
    it('extrait companyName et les IRI de categories', () => {
        const draft = mapMainDraft({
            '@id': '/api/suppliers/85', id: 85,
            companyName: 'DOD862875',
            categories: [{ '@id': '/api/categories/2279', code: 'NEGOCIANT' }],
        } as SupplierDetail)
        expect(draft.companyName).toBe('DOD862875')
        expect(draft.categoryIris).toEqual(['/api/categories/2279'])
    })

    it('gere les cles omises (skip_null_values) sans planter', () => {
        const draft = mapMainDraft({ '@id': '/api/suppliers/2', id: 2 } as SupplierDetail)
        expect(draft.companyName).toBeNull()
        expect(draft.categoryIris).toEqual([])
    })
})

describe('mapInformationDraft — pre-remplissage onglet Information (+ volumeForecast M2)', () => {
    it('tronque foundedAt, stringifie employeesCount et volumeForecast', () => {
        const draft = mapInformationDraft({
            '@id': '/api/suppliers/85', id: 85,
            foundedAt: '2008-04-01T00:00:00+02:00', employeesCount: 42, volumeForecast: 8000,
        } as SupplierDetail)
        expect(draft.foundedAt).toBe('2008-04-01')
        expect(draft.employeesCount).toBe('42')
        expect(draft.volumeForecast).toBe('8000')
    })

    it('cles omises -> null (volumeForecast inclus)', () => {
        const draft = mapInformationDraft({ '@id': '/api/suppliers/1', id: 1 } as SupplierDetail)
        expect(draft.foundedAt).toBeNull()
        expect(draft.employeesCount).toBeNull()
        expect(draft.volumeForecast).toBeNull()
        expect(draft.description).toBeNull()
    })
})

describe('mapAccountingFormDraft — pre-remplissage onglet Comptabilite', () => {
    it('extrait les scalaires et les IRI des referentiels embarques', () => {
        const draft = mapAccountingFormDraft({
            '@id': '/api/suppliers/85', id: 85,
            siren: '123456789', accountNumber: 'F0001', nTva: 'FR00123456789',
            tvaMode: { '@id': '/api/tva_modes/30', label: 'France (ventes)' },
            paymentType: '/api/payment_types/14',
        } as SupplierDetail)
        expect(draft.siren).toBe('123456789')
        expect(draft.tvaModeIri).toBe('/api/tva_modes/30')
        expect(draft.paymentTypeIri).toBe('/api/payment_types/14')
        expect(draft.bankIri).toBeNull()
    })

    it('cles comptables absentes (gating par omission) -> scalaires/IRI null', () => {
        const draft = mapAccountingFormDraft({ '@id': '/api/suppliers/1', id: 1 } as SupplierDetail)
        expect(draft.siren).toBeNull()
        expect(draft.tvaModeIri).toBeNull()
        expect(draft.bankIri).toBeNull()
    })
})

describe('resolveTabEditability — gating par role (matrice § 2.7)', () => {
    it('Admin : tout editable', () => {
        expect(resolveTabEditability({ canManage: true, canAccountingView: true, canAccountingManage: true }))
            .toEqual({ businessEditable: true, accountingVisible: true, accountingEditable: true })
    })

    it('Bureau / Commerciale (manage seul) : metier editable, Comptabilite masquee', () => {
        expect(resolveTabEditability({ canManage: true, canAccountingView: false, canAccountingManage: false }))
            .toEqual({ businessEditable: true, accountingVisible: false, accountingEditable: false })
    })

    it('Compta (accounting seul) : metier readonly, Comptabilite editable', () => {
        expect(resolveTabEditability({ canManage: false, canAccountingView: true, canAccountingManage: true }))
            .toEqual({ businessEditable: false, accountingVisible: true, accountingEditable: true })
    })

    it('Sans permission d\'edition : rien d\'editable', () => {
        expect(resolveTabEditability({ canManage: false, canAccountingView: false, canAccountingManage: false }))
            .toEqual({ businessEditable: false, accountingVisible: false, accountingEditable: false })
    })
})
