import { describe, it, expect, vi } from 'vitest'
import { removeCollectionRow, isRowRemovable, type DeletableRow } from '../collectionRow'

/**
 * Tests de `removeCollectionRow` — suppression d'une ligne de collection
 * (contact / adresse / RIB) avec DELETE immediat de la sous-ressource existante
 * (ERP-172). Coeur de logique mutualise par les 3 modules (Client / Fournisseur /
 * Prestataire) : un seul comportement teste ici couvre les 9 cas (3 modules x 3
 * blocs).
 */
interface Row extends DeletableRow {
    label?: string
}

function makeEmpty(): Row {
    return { id: null, label: '' }
}

describe('removeCollectionRow', () => {
    it('emet un DELETE sur la sous-ressource quand le bloc est existant (id non null)', async () => {
        const rows: Row[] = [{ id: 10, label: 'A' }, { id: 11, label: 'B' }]
        const errors: Record<string, string>[] = [{}, {}]
        const deleteRow = vi.fn().mockResolvedValue(undefined)
        const onError = vi.fn()

        const removed = await removeCollectionRow({
            rows, errors, index: 0,
            endpoint: '/client_contacts',
            deleteRow, makeEmpty, onError,
        })

        expect(deleteRow).toHaveBeenCalledOnce()
        expect(deleteRow).toHaveBeenCalledWith('/client_contacts/10')
        expect(removed).toBe(true)
        expect(rows).toEqual([{ id: 11, label: 'B' }])
        expect(errors).toHaveLength(1)
        expect(onError).not.toHaveBeenCalled()
    })

    it('ne fait AUCUN appel reseau pour un bloc jamais persiste (id null) — retrait local', async () => {
        const rows: Row[] = [{ id: 10, label: 'A' }, { id: null, label: 'brouillon' }]
        const errors: Record<string, string>[] = [{}, {}]
        const deleteRow = vi.fn().mockResolvedValue(undefined)
        const onError = vi.fn()

        const removed = await removeCollectionRow({
            rows, errors, index: 1,
            endpoint: '/client_contacts',
            deleteRow, makeEmpty, onError,
        })

        expect(deleteRow).not.toHaveBeenCalled()
        expect(removed).toBe(true)
        expect(rows).toEqual([{ id: 10, label: 'A' }])
    })

    it('conserve le bloc et remonte l\'erreur si le DELETE serveur echoue (ex. 409 dernier RIB LCR)', async () => {
        const rows: Row[] = [{ id: 10, label: 'A' }, { id: 11, label: 'B' }]
        const errors: Record<string, string>[] = [{}, {}]
        const error = { response: { status: 409 } }
        const deleteRow = vi.fn().mockRejectedValue(error)
        const onError = vi.fn()

        const removed = await removeCollectionRow({
            rows, errors, index: 0,
            endpoint: '/client_ribs',
            deleteRow, makeEmpty, onError,
        })

        expect(removed).toBe(false)
        expect(onError).toHaveBeenCalledWith(error)
        // Bloc NON retire : la suppression n'a pas ete confirmee par le serveur.
        expect(rows).toEqual([{ id: 10, label: 'A' }, { id: 11, label: 'B' }])
        expect(errors).toHaveLength(2)
    })

    it('garde au moins un bloc visible apres retrait du dernier (amorce vide)', async () => {
        const rows: Row[] = [{ id: 10, label: 'A' }]
        const errors: Record<string, string>[] = [{}]
        const deleteRow = vi.fn().mockResolvedValue(undefined)

        await removeCollectionRow({
            rows, errors, index: 0,
            endpoint: '/client_contacts',
            deleteRow, makeEmpty, onError: vi.fn(),
        })

        expect(rows).toEqual([{ id: null, label: '' }])
    })
})

/**
 * Tests de `isRowRemovable` — la poubelle d'un bloc n'apparait que s'il reste un
 * AUTRE bloc deja enregistre (id en base). Empeche de supprimer un bloc tant que
 * rien n'est sauvegarde, et de supprimer son dernier bloc enregistre (ERP-172).
 */
describe('isRowRemovable', () => {
    it('faux quand aucun autre bloc n\'est enregistre (que des brouillons)', () => {
        const rows: Row[] = [{ id: null, label: 'brouillon 1' }, { id: null, label: 'brouillon 2' }]
        expect(isRowRemovable(rows, 0)).toBe(false)
        expect(isRowRemovable(rows, 1)).toBe(false)
    })

    it('faux pour le seul bloc enregistre (un brouillon a cote ne compte pas)', () => {
        const rows: Row[] = [{ id: 10, label: 'enregistre' }, { id: null, label: 'brouillon' }]
        // Le bloc enregistre ne peut pas etre supprime : aucun AUTRE bloc enregistre.
        expect(isRowRemovable(rows, 0)).toBe(false)
        // Le brouillon peut etre jete : il reste le bloc enregistre id=10.
        expect(isRowRemovable(rows, 1)).toBe(true)
    })

    it('vrai pour chaque bloc des qu\'au moins deux sont enregistres', () => {
        const rows: Row[] = [{ id: 10, label: 'A' }, { id: 11, label: 'B' }]
        expect(isRowRemovable(rows, 0)).toBe(true)
        expect(isRowRemovable(rows, 1)).toBe(true)
    })

    it('faux pour un unique bloc', () => {
        expect(isRowRemovable([{ id: 10, label: 'A' }], 0)).toBe(false)
    })
})
