<template>
    <div>
        <!-- En-tete : retour vers le repertoire + titre. -->
        <div class="flex items-center gap-3 pt-11">
            <MalioButtonIcon
                icon="mdi:arrow-left-bold"
                icon-size="24"
                variant="ghost"
                v-bind="{ ariaLabel: t('commercial.suppliers.form.back') }"
                @click="goBack"
            />
            <h1 class="text-[30px] font-semibold text-m-primary">{{ t('commercial.suppliers.form.title') }}</h1>
        </div>

        <!-- ── Formulaire principal (pre-onglets) ─────────────────────────────
             Sans validation de ce bloc, les onglets restent inaccessibles. Au
             succes du POST, les champs passent en lecture seule et on bascule
             automatiquement sur l'onglet Information. Pas de contact inline (ERP-106). -->
        <div class="mt-[48px] grid grid-cols-3 xl:grid-cols-4 gap-x-[44px] gap-y-4">
            <MalioInputText
                v-model="main.companyName"
                :label="t('commercial.suppliers.form.main.companyName')"
                :required="true"
                :readonly="mainLocked"
                :error="mainErrors.errors.companyName"
            />
            <MalioSelectCheckbox
                :model-value="main.categoryIris"
                :options="referentials.categories.value"
                :label="t('commercial.suppliers.form.main.categories')"
                :display-tag="true"
                :readonly="mainLocked"
                :required="true"
                :error="mainErrors.errors.categories"
                @update:model-value="(v: (string | number)[]) => main.categoryIris = v.map(String)"
            />
        </div>

        <div v-if="!mainLocked" class="mt-12 flex justify-center">
            <MalioButton
                variant="primary"
                :label="t('commercial.suppliers.form.submit')"
                :disabled="mainSubmitting"
                @click="submitMain"
            />
        </div>

        <!-- ── Onglets a validation incrementale ─────────────────────────────-->
        <MalioTabList v-model="activeTab" :tabs="tabs" class="mt-[60px]">
            <!-- Onglet Information -->
            <template #information>
                <div class="mt-12 grid grid-cols-4 gap-x-[44px] gap-y-4 bg-white py-4 pl-[28px] pr-[60px] shadow-[0_4px_4px_0_rgba(0,0,0,0.25)]">
                    <MalioInputTextArea
                        v-model="information.description"
                        :label="t('commercial.suppliers.form.information.description')"
                        resize="none"
                        group-class="row-span-2 pt-1 pb-1"
                        text-input="h-full text-lg"
                        :readonly="isValidated('information')"
                        :error="informationErrors.errors.description"
                    />
                    <MalioInputText
                        v-model="information.competitors"
                        :label="t('commercial.suppliers.form.information.competitors')"
                        :readonly="isValidated('information')"
                        :error="informationErrors.errors.competitors"
                    />
                    <MalioDate
                        v-model="information.foundedAt"
                        :label="t('commercial.suppliers.form.information.foundedAt')"
                        :readonly="isValidated('information')"
                        :editable="true"
                        :error="informationErrors.errors.foundedAt"
                        @update:raw-value="(v: string) => information.foundedAtRaw = v"
                    />
                    <MalioInputText
                        v-model="information.employeesCount"
                        :label="t('commercial.suppliers.form.information.employeesCount')"
                        :mask="EMPLOYEES_MASK"
                        :readonly="isValidated('information')"
                        :error="informationErrors.errors.employeesCount"
                    />
                    <MalioInputAmount
                        v-model="information.revenueAmount"
                        :label="t('commercial.suppliers.form.information.revenueAmount')"
                        :readonly="isValidated('information')"
                        :error="informationErrors.errors.revenueAmount"
                    />
                    <MalioInputText
                        v-model="information.directorName"
                        :label="t('commercial.suppliers.form.information.directorName')"
                        :readonly="isValidated('information')"
                        :error="informationErrors.errors.directorName"
                    />
                    <MalioInputAmount
                        v-model="information.profitAmount"
                        :label="t('commercial.suppliers.form.information.profitAmount')"
                        :readonly="isValidated('information')"
                        :error="informationErrors.errors.profitAmount"
                    />
                    <!-- Volume previsionnel : specifique fournisseur. Champ texte
                         masque (chiffres uniquement) ; l'entier est resolu au PATCH. -->
                    <MalioInputText
                        v-model="information.volumeForecast"
                        :label="t('commercial.suppliers.form.information.volumeForecast')"
                        :mask="VOLUME_FORECAST_MASK"
                        :readonly="isValidated('information')"
                        :error="informationErrors.errors.volumeForecast"
                    />
                </div>
                <div v-if="!isValidated('information')" class="mt-12 flex justify-center">
                    <MalioButton
                        variant="primary"
                        :label="t('commercial.suppliers.form.submit')"
                        :disabled="tabSubmitting || supplierId === null"
                        @click="submitInformation"
                    />
                </div>
            </template>

            <!-- Onglet Contacts -->
            <template #contacts>
                <div class="mt-12 flex flex-col gap-6">
                    <!-- ERP-172 : poubelle visible seulement s'il reste un AUTRE bloc deja
                         enregistre (id en base) — cf. isRowRemovable. Empeche de supprimer un
                         bloc tant que rien n'est sauvegarde, et de supprimer son dernier
                         bloc enregistre. -->
                    <SupplierContactBlock
                        v-for="(contact, index) in contacts"
                        :key="index"
                        :model-value="contact"
                        :title="t('commercial.suppliers.form.contact.title', { n: index + 1 })"
                        :removable="isRowRemovable(contacts, index)"
                        :readonly="isValidated('contacts')"
                        :errors="contactErrors[index]"
                        @update:model-value="(v) => contacts[index] = v"
                        @remove="askRemoveContact(index)"
                    />
                    <div v-if="!isValidated('contacts')" class="flex justify-center gap-6">
                        <MalioButton
                            variant="secondary"
                            icon-name="mdi:add-bold"
                            icon-position="left"
                            :label="t('commercial.suppliers.form.contact.add')"
                            :disabled="!canAddContact"
                            @click="addContact"
                        />
                        <MalioButton
                            variant="primary"
                            :label="t('commercial.suppliers.form.submit')"
                            :disabled="tabSubmitting"
                            @click="submitContacts"
                        />
                    </div>
                </div>
            </template>

            <!-- Onglet Adresses -->
            <template #addresses>
                <div class="mt-12 flex flex-col gap-6">
                    <SupplierAddressBlock
                        v-for="(address, index) in addresses"
                        :key="index"
                        :model-value="address"
                        :title="t('commercial.suppliers.form.address.title', { n: index + 1 })"
                        :category-options="referentials.categories.value"
                        :site-options="referentials.sites.value"
                        :contact-options="contactOptions"
                        :country-options="countryOptions"
                        :removable="isRowRemovable(addresses, index)"
                        :readonly="isValidated('addresses')"
                        :errors="addressErrors[index]"
                        @update:model-value="(v) => addresses[index] = v"
                        @remove="askRemoveAddress(index)"
                        @degraded="onAddressDegraded"
                    />
                    <div v-if="!isValidated('addresses')" class="flex justify-center gap-6">
                        <MalioButton
                            variant="secondary"
                            icon-name="mdi:add-bold"
                            icon-position="left"
                            :label="t('commercial.suppliers.form.address.add')"
                            :disabled="!canAddAddress"
                            @click="addAddress"
                        />
                        <MalioButton
                            variant="primary"
                            :label="t('commercial.suppliers.form.submit')"
                            :disabled="tabSubmitting"
                            @click="submitAddresses"
                        />
                    </div>
                </div>
            </template>

            <!-- Onglet Comptabilite (present uniquement si accounting.view) -->
            <template v-if="canAccountingView" #accounting>
                <div class="mt-12 flex flex-col gap-6">
                    <div class="bg-white py-4 pl-[28px] pr-[60px] shadow-[0_4px_4px_0_rgba(0,0,0,0.25)]">
                        <div class="grid grid-cols-4 gap-x-[44px] gap-y-4">
                            <MalioInputText
                                v-model="accounting.siren"
                                :label="t('commercial.suppliers.form.accounting.siren')"
                                :mask="SIREN_MASK"
                                :readonly="accountingReadonly"
                                :required="true"
                                :error="accountingErrors.errors.siren"
                            />
                            <MalioInputText
                                v-model="accounting.accountNumber"
                                :label="t('commercial.suppliers.form.accounting.accountNumber')"
                                :readonly="accountingReadonly"
                                :required="true"
                                :error="accountingErrors.errors.accountNumber"
                            />
                            <MalioSelect
                                :model-value="accounting.tvaModeIri"
                                :options="referentials.tvaModes.value"
                                :label="t('commercial.suppliers.form.accounting.tvaMode')"
                                :readonly="accountingReadonly"
                                empty-option-label=""
                                :required="true"
                                :error="accountingErrors.errors.tvaMode"
                                @update:model-value="(v: string | number | null) => accounting.tvaModeIri = v === null ? null : String(v)"
                            />
                            <MalioInputText
                                v-model="accounting.nTva"
                                :label="t('commercial.suppliers.form.accounting.nTva')"
                                :readonly="accountingReadonly"
                                :required="true"
                                :error="accountingErrors.errors.nTva"
                            />
                            <MalioSelect
                                :model-value="accounting.paymentDelayIri"
                                :options="referentials.paymentDelays.value"
                                :label="t('commercial.suppliers.form.accounting.paymentDelay')"
                                :readonly="accountingReadonly"
                                empty-option-label=""
                                :required="true"
                                :error="accountingErrors.errors.paymentDelay"
                                @update:model-value="(v: string | number | null) => accounting.paymentDelayIri = v === null ? null : String(v)"
                            />
                            <MalioSelect
                                :model-value="accounting.paymentTypeIri"
                                :options="referentials.paymentTypes.value"
                                :label="t('commercial.suppliers.form.accounting.paymentType')"
                                :readonly="accountingReadonly"
                                empty-option-label=""
                                :required="true"
                                :error="accountingErrors.errors.paymentType"
                                @update:model-value="onPaymentTypeChange"
                            />
                            <MalioSelect
                                v-if="isBankRequired"
                                :model-value="accounting.bankIri"
                                :options="referentials.banks.value"
                                :label="t('commercial.suppliers.form.accounting.bank')"
                                :readonly="accountingReadonly"
                                empty-option-label=""
                                :required="true"
                                :error="accountingErrors.errors.bank"
                                @update:model-value="(v: string | number | null) => accounting.bankIri = v === null ? null : String(v)"
                            />
                        </div>
                    </div>

                    <!-- Blocs RIB — affiches uniquement si type de reglement = LCR (RG-2.08). -->
                    <div
                        v-for="(rib, index) in visibleRibs"
                        :key="index"
                        class="relative bg-white py-4 pl-[28px] pr-[60px] shadow-[0_4px_4px_0_rgba(0,0,0,0.25)]"
                    >
                        <MalioButtonIcon
                            v-if="!accountingReadonly && isRowRemovable(visibleRibs, index)"
                            icon="mdi:delete-outline"
                            variant="ghost"
                            button-class="absolute top-3 right-3"
                            v-bind="{ ariaLabel: t('commercial.suppliers.form.accounting.removeRib') }"
                            @click="askRemoveRib(index)"
                        />
                        <div class="grid grid-cols-4 gap-x-[44px] gap-y-4">
                            <MalioInputText
                                v-model="rib.label"
                                :label="t('commercial.suppliers.form.accounting.ribLabel')"
                                :readonly="accountingReadonly"
                                :required="isRibRequired"
                                :error="ribErrors[index]?.label"
                            />
                            <MalioInputText
                                v-model="rib.bic"
                                :label="t('commercial.suppliers.form.accounting.ribBic')"
                                :readonly="accountingReadonly"
                                :required="isRibRequired"
                                :error="ribErrors[index]?.bic"
                            />
                            <MalioInputText
                                v-model="rib.iban"
                                :label="t('commercial.suppliers.form.accounting.ribIban')"
                                :readonly="accountingReadonly"
                                :required="isRibRequired"
                                :error="ribErrors[index]?.iban"
                            />
                        </div>
                    </div>

                    <div v-if="!accountingReadonly" class="flex justify-center gap-6">
                        <MalioButton
                            v-if="isRibRequired"
                            variant="secondary"
                            icon-name="mdi:add-bold"
                            icon-position="left"
                            :label="t('commercial.suppliers.form.accounting.addRib')"
                            :disabled="!canAddRib"
                            @click="addRib"
                        />
                        <MalioButton
                            variant="primary"
                            :label="t('commercial.suppliers.form.submit')"
                            :disabled="tabSubmitting"
                            @click="submitAccounting"
                        />
                    </div>
                </div>
            </template>

            <!-- Onglet placeholder : frame vide, passage automatique. -->
            <template #transport><ComingSoonPlaceholder /></template>
        </MalioTabList>

        <!-- Modal de confirmation generique (suppression contact/adresse/RIB). -->
        <MalioModal v-model="confirmModal.open" modal-class="max-w-md">
            <template #header>
                <h2 class="text-[24px] font-bold">{{ t('commercial.suppliers.form.confirmDelete.title') }}</h2>
            </template>
            <p>{{ confirmModal.message }}</p>
            <template #footer>
                <MalioButton
                    variant="secondary"
                    button-class="flex-1"
                    :label="t('commercial.suppliers.form.confirmDelete.cancel')"
                    @click="confirmModal.open = false"
                />
                <MalioButton
                    variant="danger"
                    button-class="flex-1"
                    :label="t('commercial.suppliers.form.confirmDelete.confirm')"
                    @click="runConfirm"
                />
            </template>
        </MalioModal>
    </div>
</template>

<script setup lang="ts">
import { computed, onMounted, reactive, ref, watch } from 'vue'
import { useSupplierReferentials, type RefOption } from '~/modules/commercial/composables/useSupplierReferentials'
import { useSupplierFormErrors } from '~/modules/commercial/composables/useSupplierFormErrors'
import {
    buildSupplierFormTabKeys,
    SUPPLIER_FORM_PLACEHOLDER_TABS,
    isAddressValid,
    isBankRequiredForPaymentType,
    isContactBlank,
    isContactNamed,
    isRibBlank,
    isRibComplete,
    isRibRequiredForPaymentType,
    lastFillableTabKey,
} from '~/modules/commercial/utils/forms/supplierFormRules'
import {
    buildAccountingPayload,
    buildAddressPayload,
    buildContactPayload,
    buildInformationPayload,
    buildMainPayload,
    buildRibPayload,
} from '~/modules/commercial/utils/forms/supplierEdit'
import {
    emptyAddress,
    emptyContact,
    emptyRib,
    type SupplierAddressFormDraft,
    type SupplierContactFormDraft,
    type SupplierRibFormDraft,
} from '~/modules/commercial/types/supplierForm'
import { extractApiErrorMessage } from '~/shared/utils/api'
import { isRowRemovable } from '~/shared/utils/collectionRow'

// Masques de saisie (la normalisation finale reste serveur).
const SIREN_MASK = '#########'
const EMPLOYEES_MASK = '#######'
// Volume previsionnel : champ texte borne aux chiffres (entier >= 0 cote back).
const VOLUME_FORECAST_MASK = '##########'

const { t } = useI18n()
const api = useApi()
const toast = useToast()
const router = useRouter()
const { can } = usePermissions()

/** Retour vers le repertoire fournisseurs (fleche d'en-tete). */
function goBack(): void {
    router.push('/suppliers')
}

/**
 * Message d'erreur a afficher dans un toast a partir d'une erreur d'API. Retourne
 * TOUJOURS une chaine (le composant de toast plante sur `undefined`).
 */
function apiErrorMessage(error: unknown): string {
    const data = (error as { data?: unknown })?.data
    return extractApiErrorMessage(data) || t('commercial.suppliers.toast.error')
}

// ── Erreurs de validation par champ (ERP-101) ───────────────────────────────
const {
    mainErrors,
    informationErrors,
    accountingErrors,
    contactErrors,
    addressErrors,
    ribErrors,
    submitRows,
} = useSupplierFormErrors()

useHead({ title: t('commercial.suppliers.form.title') })

// Gating de la route : la creation est reservee a `manage`. Compta (accounting
// seul) et Usine sont rediriges vers le repertoire.
if (!can('commercial.suppliers.manage')) {
    await navigateTo('/suppliers')
}

const canAccountingView = computed(() => can('commercial.suppliers.accounting.view'))
const canAccountingManage = computed(() => can('commercial.suppliers.accounting.manage'))

const referentials = useSupplierReferentials()

// ── Etat du fournisseur cree ────────────────────────────────────────────────
const supplierId = ref<number | null>(null)
const mainLocked = ref(false)
const mainSubmitting = ref(false)
const tabSubmitting = ref(false)

// ── Formulaire principal ────────────────────────────────────────────────────
const main = reactive({
    companyName: null as string | null,
    categoryIris: [] as string[],
})

/** POST /suppliers (groupe supplier:write:main). Au succes : verrouille + bascule Information. */
async function submitMain(): Promise<void> {
    if (mainSubmitting.value) return
    mainSubmitting.value = true
    mainErrors.clearErrors()
    try {
        const created = await api.post<SupplierResponse>('/suppliers', buildMainPayload(main), {
            headers: { Accept: 'application/ld+json' },
            toast: false,
        })

        supplierId.value = created.id
        // Reaffiche la valeur normalisee renvoyee par le serveur (UPPERCASE, RG-2.12).
        main.companyName = created.companyName ?? main.companyName

        mainLocked.value = true
        // Information est facultatif : on deverrouille jusqu'a Contacts (index 1).
        unlockedIndex.value = tabIndex('contacts')
        activeTab.value = 'information'
        toast.success({ title: t('commercial.suppliers.toast.createSuccess') })
    }
    catch (error) {
        // 409 = doublon nom de societe (RG d'unicite) → erreur inline + toast ;
        // 422 → mapping inline par champ ; autre → toast de fallback (ERP-101).
        const status = (error as { response?: { status?: number } })?.response?.status
        if (status === 409) {
            const message = t('commercial.suppliers.form.duplicateCompany')
            mainErrors.setError('companyName', message)
            toast.error({ title: t('commercial.suppliers.toast.error'), message })
        }
        else {
            mainErrors.handleApiError(error, { fallbackMessage: t('commercial.suppliers.toast.error') })
        }
    }
    finally {
        mainSubmitting.value = false
    }
}

// ── Onglets : ordre + gating progressif ─────────────────────────────────────
const activeTab = ref('information')
// Index du dernier onglet deverrouille (-1 tant que le fournisseur n'est pas cree).
const unlockedIndex = ref(-1)
// Onglets valides (passent en lecture seule).
const validated = reactive<Record<string, boolean>>({})

const tabKeys = computed(() => buildSupplierFormTabKeys(canAccountingView.value))

// Dernier onglet REMPLISSABLE par le role : sa validation cloture l'ajout.
const lastFillableTab = computed(() => lastFillableTabKey(tabKeys.value))

// Icone (Iconify) affichee dans l'onglet, par cle.
const TAB_ICONS: Record<string, string> = {
    information: 'mdi:account-outline',
    contacts: 'mdi:account-box-plus-outline',
    addresses: 'mdi:map-marker-outline',
    transport: 'mdi:truck-delivery-outline',
    accounting: 'mdi:bank-circle-outline',
}

const tabs = computed(() => tabKeys.value.map((key, index) => ({
    key,
    label: t(`commercial.suppliers.tab.${key}`),
    icon: TAB_ICONS[key],
    disabled: index > unlockedIndex.value,
})))

function isValidated(key: string): boolean {
    return validated[key] === true
}

function tabIndex(key: string): number {
    return tabKeys.value.indexOf(key)
}

/**
 * Marque l'onglet valide. Si c'est le dernier onglet remplissable, l'ajout est
 * termine : toast final + redirection vers la liste, et on retourne true. Sinon,
 * deverrouille et avance a l'onglet suivant, et retourne false.
 */
function completeTab(key: string): boolean {
    validated[key] = true
    if (key === lastFillableTab.value) {
        toast.success({ title: t('commercial.suppliers.toast.addComplete') })
        router.push('/suppliers')
        return true
    }
    const next = tabKeys.value[tabIndex(key) + 1]
    unlockedIndex.value = Math.max(unlockedIndex.value, tabIndex(key) + 1)
    if (next) activeTab.value = next
    return false
}

// Passage automatique sur les onglets coquille (Transport).
watch(activeTab, (key) => {
    if ((SUPPLIER_FORM_PLACEHOLDER_TABS as readonly string[]).includes(key)) {
        const next = tabKeys.value[tabIndex(key) + 1]
        unlockedIndex.value = Math.max(unlockedIndex.value, tabIndex(key) + 1)
        if (next) activeTab.value = next
    }
})

// ── Onglet Information ──────────────────────────────────────────────────────
const information = reactive({
    description: null as string | null,
    competitors: null as string | null,
    foundedAt: null as string | null,
    // Saisie brute invalide remontee par MalioDate (cf. foundedAtRaw, MUI-44).
    foundedAtRaw: '',
    employeesCount: null as string | null,
    revenueAmount: null as string | null,
    profitAmount: null as string | null,
    directorName: null as string | null,
    volumeForecast: null as string | null,
})

/** PATCH /suppliers/{id} — mode strict : uniquement les champs du groupe information. */
async function submitInformation(): Promise<void> {
    if (supplierId.value === null || tabSubmitting.value) return
    tabSubmitting.value = true
    informationErrors.clearErrors()
    try {
        await api.patch(`/suppliers/${supplierId.value}`, buildInformationPayload(information), { toast: false })
        if (completeTab('information')) return
        toast.success({ title: t('commercial.suppliers.toast.updateSuccess') })
    }
    catch (error) {
        informationErrors.handleApiError(error, { fallbackMessage: t('commercial.suppliers.toast.error') })
    }
    finally {
        tabSubmitting.value = false
    }
}

// ── Onglet Contacts ─────────────────────────────────────────────────────────
const contacts = ref<SupplierContactFormDraft[]>([emptyContact()])

// « + Nouveau contact » desactive tant que le dernier bloc n'a ni nom ni prenom.
const canAddContact = computed(() => {
    const last = contacts.value[contacts.value.length - 1]
    return last !== undefined && isContactNamed(last)
})

function addContact(): void {
    if (canAddContact.value) contacts.value.push(emptyContact())
}

function askRemoveContact(index: number): void {
    askConfirm(t('commercial.suppliers.form.confirmDelete.contact'), () => {
        contacts.value.splice(index, 1)
        contactErrors.value.splice(index, 1)
    })
}

/** POST/PATCH des contacts sur la sous-ressource /suppliers/{id}/contacts. */
async function submitContacts(): Promise<void> {
    if (supplierId.value === null || tabSubmitting.value) return
    tabSubmitting.value = true
    try {
        // RG-2.13 : au moins un contact requis. Si l'onglet ne contient QUE des
        // amorces vides, on les soumet pour declencher la 422 RG-2.04 inline.
        const hasSubmittableContact = contacts.value.some(c => c.id !== null || !isContactBlank(c))
        const hasError = await submitRows(
            contacts.value,
            contactErrors,
            async (contact) => {
                const body = buildContactPayload(contact)
                if (contact.id === null) {
                    const created = await api.post<ContactResponse>(
                        `/suppliers/${supplierId.value}/contacts`,
                        body,
                        { headers: { Accept: 'application/ld+json' }, toast: false },
                    )
                    contact.id = created.id
                    contact.iri = created['@id'] ?? null
                }
                else {
                    await api.patch(`/supplier_contacts/${contact.id}`, body, { toast: false })
                }
            },
            error => toast.error({ title: t('commercial.suppliers.toast.error'), message: apiErrorMessage(error) }),
            contact => hasSubmittableContact && contact.id === null && isContactBlank(contact),
        )
        if (hasError) return
        if (completeTab('contacts')) return
        toast.success({ title: t('commercial.suppliers.toast.updateSuccess') })
    }
    finally {
        tabSubmitting.value = false
    }
}

// ── Onglet Adresses ─────────────────────────────────────────────────────────
const addresses = ref<SupplierAddressFormDraft[]>([emptyAddress()])
const addressDegradedNotified = ref(false)

// Contacts deja crees, rattachables a une adresse (M2M, via leur IRI).
const contactOptions = computed<RefOption[]>(() =>
    contacts.value
        .filter(c => c.iri !== null)
        .map(c => ({
            value: c.iri as string,
            label: [c.firstName, c.lastName].filter(Boolean).join(' ') || (c.email ?? ''),
        })),
)

// Pays : referentiel `country` charge via l'API (ERP-116), aligne sur l'ecran
// client. France garantie en tete pour rester preselectionnable par defaut sur
// chaque adresse meme si `/countries` echoue (resilience ERP-102).
const countryOptions = computed<RefOption[]>(() => {
    const list = referentials.countries.value
    return list.some(c => c.value === 'France')
        ? list
        : [{ value: 'France', label: 'France' }, ...list]
})

// « + Adresse » desactive tant que la derniere adresse n'est pas valide.
const canAddAddress = computed(() => {
    const last = addresses.value[addresses.value.length - 1]
    return last !== undefined && isAddressValid(last)
})

function addAddress(): void {
    if (canAddAddress.value) addresses.value.push(emptyAddress())
}

function askRemoveAddress(index: number): void {
    askConfirm(t('commercial.suppliers.form.confirmDelete.address'), () => {
        addresses.value.splice(index, 1)
        addressErrors.value.splice(index, 1)
    })
}

/** Avertit une seule fois quand l'autocompletion d'adresse bascule en degrade. */
function onAddressDegraded(): void {
    if (addressDegradedNotified.value) return
    addressDegradedNotified.value = true
    toast.warning({
        title: t('commercial.suppliers.toast.error'),
        message: t('commercial.suppliers.form.address.degraded'),
    })
}

/** POST/PATCH des adresses sur la sous-ressource /suppliers/{id}/addresses. */
async function submitAddresses(): Promise<void> {
    if (supplierId.value === null || tabSubmitting.value) return
    tabSubmitting.value = true
    try {
        const hasError = await submitRows(
            addresses.value,
            addressErrors,
            async (address) => {
                const body = buildAddressPayload(address)
                if (address.id === null) {
                    const created = await api.post<{ id: number }>(
                        `/suppliers/${supplierId.value}/addresses`,
                        body,
                        { headers: { Accept: 'application/ld+json' }, toast: false },
                    )
                    address.id = created.id
                }
                else {
                    await api.patch(`/supplier_addresses/${address.id}`, body, { toast: false })
                }
            },
            error => toast.error({ title: t('commercial.suppliers.toast.error'), message: apiErrorMessage(error) }),
        )
        if (hasError) return
        if (completeTab('addresses')) return
        toast.success({ title: t('commercial.suppliers.toast.updateSuccess') })
    }
    finally {
        tabSubmitting.value = false
    }
}

// ── Onglet Comptabilite ─────────────────────────────────────────────────────
const accounting = reactive({
    siren: null as string | null,
    accountNumber: null as string | null,
    tvaModeIri: null as string | null,
    nTva: null as string | null,
    paymentDelayIri: null as string | null,
    paymentTypeIri: null as string | null,
    bankIri: null as string | null,
})
const ribs = ref<SupplierRibFormDraft[]>([])

// L'onglet est editable seulement avec accounting.manage (sinon lecture seule).
const accountingReadonly = computed(() => isValidated('accounting') || !canAccountingManage.value)

// Code du type de reglement selectionne (pour RG-2.07 / RG-2.08).
const selectedPaymentTypeCode = computed(() =>
    referentials.paymentTypes.value.find(p => p.value === accounting.paymentTypeIri)?.code ?? null,
)
const isBankRequired = computed(() => isBankRequiredForPaymentType(selectedPaymentTypeCode.value))
const isRibRequired = computed(() => isRibRequiredForPaymentType(selectedPaymentTypeCode.value))

// Les blocs RIB ne sont affiches que pour une LCR (RG-2.08).
const visibleRibs = computed(() => isRibRequired.value ? ribs.value : [])

function onPaymentTypeChange(value: string | number | null): void {
    accounting.paymentTypeIri = value === null ? null : String(value)
    // La banque n'a de sens que pour un virement : on la vide sinon (RG-2.07).
    if (!isBankRequired.value) accounting.bankIri = null
    // ERP-121 : on ne jette plus la saisie RIB au passage hors-LCR. Les blocs sont
    // masques (visibleRibs = []) mais conserves, et reapparaissent si l'on repasse
    // en LCR. Ils ne sont persistes qu'a la validation SOUS LCR (cf. submitAccounting),
    // donc une saisie abandonnee hors-LCR ne cree aucun RIB orphelin.
    if (isRibRequired.value) {
        if (ribs.value.length === 0) ribs.value.push(emptyRib())
    }
    else {
        ribErrors.value = []
    }
}

// « + RIB » desactive tant que le dernier bloc RIB n'est pas complet.
const canAddRib = computed(() => {
    const last = ribs.value[ribs.value.length - 1]
    return last !== undefined && isRibComplete(last)
})

function addRib(): void {
    if (canAddRib.value) ribs.value.push(emptyRib())
}

function askRemoveRib(index: number): void {
    askConfirm(t('commercial.suppliers.form.confirmDelete.rib'), () => {
        ribs.value.splice(index, 1)
        ribErrors.value.splice(index, 1)
        // Garde au moins un bloc RIB visible.
        if (ribs.value.length === 0) ribs.value.push(emptyRib())
    })
}

/**
 * Valide l'onglet Comptabilite : POST/PATCH des RIB sur /suppliers/{id}/ribs PUIS
 * PATCH des scalaires (groupe supplier:write:accounting). Les RIB d'abord : le back
 * valide RG-2.08 (LCR => au moins un RIB persiste) sur le PATCH scalaires, les RIB
 * doivent donc exister en base AVANT. Deux appels distincts (mode strict).
 */
async function submitAccounting(): Promise<void> {
    if (supplierId.value === null || tabSubmitting.value) return
    tabSubmitting.value = true
    accountingErrors.clearErrors()
    try {
        // 1) POST/PATCH des RIB d'abord — UNIQUEMENT sous LCR (erreurs inline par
        // ligne). Hors-LCR (ERP-121), une saisie RIB eventuellement restee dans le
        // brouillon est masquee et n'est PAS persistee (pas de RIB orphelin sur un
        // fournisseur en virement). On ne saute une amorce neuve vide QUE s'il reste
        // un autre RIB soumettable : sinon (LCR sans aucun RIB rempli) on la soumet
        // pour declencher la 422 NotBlank inline.
        if (isRibRequired.value) {
            const hasSubmittableRib = ribs.value.some(r => r.id !== null || !isRibBlank(r))
            const ribHasError = await submitRows(
                ribs.value,
                ribErrors,
                async (rib) => {
                    const body = buildRibPayload(rib)
                    if (rib.id === null) {
                        const created = await api.post<{ id: number }>(
                            `/suppliers/${supplierId.value}/ribs`,
                            body,
                            { headers: { Accept: 'application/ld+json' }, toast: false },
                        )
                        rib.id = created.id
                    }
                    else {
                        await api.patch(`/supplier_ribs/${rib.id}`, body, { toast: false })
                    }
                },
                error => toast.error({ title: t('commercial.suppliers.toast.error'), message: apiErrorMessage(error) }),
                rib => hasSubmittableRib && rib.id === null && isRibBlank(rib),
            )
            if (ribHasError) return
        }

        // 2) PATCH des scalaires comptables (erreurs inline sur leurs champs).
        try {
            await api.patch(
                `/suppliers/${supplierId.value}`,
                buildAccountingPayload(accounting, isBankRequired.value),
                { toast: false },
            )
        }
        catch (error) {
            accountingErrors.handleApiError(error, { fallbackMessage: t('commercial.suppliers.toast.error') })
            return
        }

        if (completeTab('accounting')) return
        toast.success({ title: t('commercial.suppliers.toast.updateSuccess') })
    }
    finally {
        tabSubmitting.value = false
    }
}

// ── Modal de confirmation generique ─────────────────────────────────────────
const confirmModal = reactive({
    open: false,
    message: '',
    action: null as null | (() => void),
})

function askConfirm(message: string, action: () => void): void {
    confirmModal.message = message
    confirmModal.action = action
    confirmModal.open = true
}

function runConfirm(): void {
    confirmModal.action?.()
    confirmModal.action = null
    confirmModal.open = false
}

// ── Types de reponse API ────────────────────────────────────────────────────
interface SupplierResponse {
    id: number
    companyName: string | null
}

interface ContactResponse {
    '@id'?: string
    id: number
}

onMounted(() => {
    // Echec du chargement des referentiels non bloquant : les selects restent vides.
    referentials.loadCommon().catch(() => {})
})
</script>
