<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('transport.carriers.form.back') }"
                @click="goBack"
            />
            <h1 class="text-[30px] font-semibold text-m-primary">{{ t('transport.carriers.form.title') }}</h1>
        </div>

        <!-- ── Formulaire principal (pre-onglets) ─────────────────────────────
             Champs conditionnels (ERP-166) : cas LIOT (nom == LIOT) → seul
             « immatriculations » ; certification AUTRE → champ Decharge ; Affreter
             coche → indexation / contenant / volume. La certification est en lecture
             seule pour un transporteur QUALIMAT (saisie assistee, onglet Qualimat). -->
        <div class="mt-[48px] grid grid-cols-3 xl:grid-cols-4 gap-x-[44px] gap-y-4">
            <MalioInputText
                v-model="main.name"
                :mask="FREE_TEXT_MASK"
                :label="t('transport.carriers.form.main.name')"
                :required="true"
                :disabled="mainLocked"
                :error="mainErrors.errors.name"
            />

            <!-- Cas LIOT : seul le champ immatriculations est pertinent. Il occupe
                 les colonnes restantes de la ligne (3 en xl, 2 sinon) — le wrapper
                 porte le col-span car MalioInputText (inheritAttrs:false) renvoie
                 `class` sur l'input interne, pas sur la cellule de grille. -->
            <div v-if="isLiot" class="col-span-2 xl:col-span-3">
                <MalioInputText
                    v-model="main.liotPlates"
                    :mask="LIOT_PLATES_MASK"
                    :label="t('transport.carriers.form.main.liotPlates')"
                    :hint="t('transport.carriers.form.main.liotPlatesHint')"
                    :required="true"
                    :disabled="mainLocked"
                    :error="mainErrors.errors.liotPlates"
                />
            </div>

            <!-- Cas standard : certification + affretement + champs conditionnels. -->
            <template v-if="!isLiot">
                <MalioSelect
                    :model-value="main.certificationType"
                    :options="certificationOptions"
                    :label="t('transport.carriers.form.main.certificationType')"
                    empty-option-label=""
                    :required="true"
                    :disabled="certificationReadonly"
                    :error="mainErrors.errors.certificationType"
                    @update:model-value="(v: string | number | null) => main.certificationType = v === null ? null : String(v)"
                />

                <!-- Colonne 3 RÉSERVÉE à la Décharge (RG-4.02 : visible et obligatoire
                     si certification AUTRE). Si elle n'apparaît pas, on garde la colonne
                     vide (xl) pour qu'« Affréter » reste en colonne 4 de la ligne 1.
                     Upload DIFFÉRÉ (ERP-171) : le fichier choisi est mis en attente
                     et envoyé seulement à la validation du formulaire. -->
                <MalioInputUpload
                    v-if="showDischarge"
                    :model-value="dischargeFileName"
                    :label="t('transport.carriers.form.main.discharge')"
                    accept="application/pdf,image/*"
                    :required="true"
                    :disabled="mainLocked || dischargeUploading"
                    :clearable="true"
                    :error="mainErrors.errors.dischargeDocument"
                    @update:model-value="(v: string) => dischargeFileName = v"
                    @file-selected="selectDischarge"
                    @clear="onClearDischarge"
                />
                <div v-else class="hidden xl:block"></div>

                <!-- « Affréter » : toujours en colonne 4 de la ligne 1 (colonne 3
                     réservée à la décharge ci-dessus). Wrapper h-12 + centrage vertical
                     pour aligner la case sur la ligne de champ des inputs/selects. -->
                <div class="flex h-12 items-center">
                    <MalioCheckbox
                        id="carrier-is-chartered"
                        :label="t('transport.carriers.form.main.isChartered')"
                        :model-value="main.isChartered"
                        :disabled="mainLocked"
                        :reserve-message-space="false"
                        @update:model-value="(val: boolean) => main.isChartered = val"
                    />
                </div>

                <!-- RG-4.03 : champs d'affretement (ligne 2) visibles + obligatoires si
                     « Affreter ». La ligne 1 étant pleine (4 colonnes), ils démarrent
                     naturellement en colonne 1 de la ligne 2. -->
                <template v-if="showCharteredFields">
                    <!-- Indexation : montant en % (icône à droite), plafonné à 100. La
                         :key force le ré-affichage du champ contrôlé quand on plafonne
                         (sinon le modelValue inchangé n'est pas re-synchronisé par Vue). -->
                    <MalioInputAmount
                        :key="indexationKey"
                        :model-value="main.indexationRate"
                        :label="t('transport.carriers.form.main.indexationRate')"
                        icon-name="mdi:percent"
                        icon-position="right"
                        :required="true"
                        :disabled="mainLocked"
                        :error="mainErrors.errors.indexationRate"
                        @update:model-value="onIndexationInput"
                    />

                    <!-- Contenant : Benne / Fond mouvant en radios, centrés (h-12) comme
                         à l'onglet Prix (Benne par défaut). -->
                    <div>
                        <div class="flex h-12 items-center gap-4">
                            <MalioRadioButton
                                :model-value="main.containerType"
                                name="carrier-main-container"
                                value="BENNE"
                                :label="t('transport.carriers.containerType.BENNE')"
                                :disabled="mainLocked"
                                group-class="mt-0"
                                @update:model-value="(v: string | number | boolean | null) => main.containerType = v === null ? null : String(v)"
                            />
                            <MalioRadioButton
                                :model-value="main.containerType"
                                name="carrier-main-container"
                                value="FOND_MOUVANT"
                                :label="t('transport.carriers.containerType.FOND_MOUVANT')"
                                :disabled="mainLocked"
                                group-class="mt-0"
                                @update:model-value="(v: string | number | boolean | null) => main.containerType = v === null ? null : String(v)"
                            />
                        </div>
                        <p v-if="mainErrors.errors.containerType" class="ml-[2px] text-xs text-m-danger">{{ mainErrors.errors.containerType }}</p>
                    </div>

                    <!-- Volume m³ : champ texte restreint aux nombres à décimales (point). -->
                    <MalioInputText
                        :model-value="main.volumeM3"
                        :label="t('transport.carriers.form.main.volumeM3')"
                        :required="true"
                        :disabled="mainLocked"
                        :error="mainErrors.errors.volumeM3"
                        @update:model-value="(v: string) => main.volumeM3 = sanitizeDecimal(v)"
                    />
                </template>
            </template>
        </div>

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

        <!-- ── Onglets a validation incrementale ─────────────────────────────
             Barre Qualimat · Adresses · Contacts · Prix. Onglet Qualimat = saisie
             assistee (table de selection) ; Adresses / Contacts / Prix arrivent aux
             tickets suivants (placeholders « A venir »). -->
        <MalioTabList v-model="activeTab" :tabs="tabs" class="mt-[60px]">
            <!-- Onglet Qualimat : saisie assistée (recherche par nom). Composant
                 mutualisé avec l'écran de modification (ERP-172). -->
            <template #qualimat>
                <CarrierQualimatTab
                    :search-name="main.name"
                    :selected-iri="main.qualimatCarrierIri"
                    @integrate="onIntegrateQualimat"
                />
            </template>

            <!-- Onglet Adresses (ERP-167) : un bloc par adresse + BAN. RG-4.05
                 préremplissage si QUALIMAT ; RG-4.07 pas de Valider si QUALIMAT. -->
            <template #addresses>
                <div class="mt-12 flex flex-col gap-6">
                    <!-- Adresse UNIQUE (ERP-172) : un seul bloc, sans ajouter/supprimer. -->
                    <CarrierAddressBlock
                        :model-value="address"
                        :country-options="countryOptions"
                        :disabled="isQualimat || isValidated('addresses')"
                        :errors="addressErrors"
                        @update:model-value="(v) => address = v"
                        @degraded="onAddressDegraded"
                    />
                    <!-- RG-4.07 : pas de bouton Valider pour un transporteur QUALIMAT
                         (adresse copiée et persistée automatiquement). -->
                    <div v-if="!isQualimat && !isValidated('addresses')" class="flex justify-center gap-6">
                        <MalioButton
                            variant="primary"
                            :label="t('transport.carriers.form.submit')"
                            :disabled="tabSubmitting || carrierId === null"
                            @click="onSubmitAddresses"
                        />
                    </div>
                </div>
            </template>

            <!-- Onglet Contacts (ERP-168) : un bloc par contact (bloc optionnel,
                 ERP-193 ; max 2 téléphones). Erreurs 422 par ligne. -->
            <template #contacts>
                <div class="mt-12 flex flex-col gap-6">
                    <CarrierContactBlock
                        v-for="(contact, index) in contacts"
                        :key="index"
                        :model-value="contact"
                        :removable="isRowRemovable(contacts, index)"
                        :disabled="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('transport.carriers.form.contact.add')"
                            :disabled="!canAddContact"
                            @click="addContact"
                        />
                        <MalioButton
                            variant="primary"
                            :label="t('transport.carriers.form.submit')"
                            :disabled="tabSubmitting || carrierId === null"
                            @click="onSubmitContacts"
                        />
                    </div>
                </div>
            </template>

            <!-- Onglet Prix (ERP-169) : blocs multiples, branche CLIENT/FOURNISSEUR
                 (RG-4.09→4.11). Démarre vide ; l'utilisateur ajoute via « + Nouveau prix ». -->
            <template #prices>
                <div class="mt-12 flex flex-col gap-6">
                    <CarrierPriceBlock
                        v-for="(price, index) in prices"
                        :key="index"
                        :model-value="price"
                        :client-options="clientOptions"
                        :supplier-options="supplierOptions"
                        :site-options="siteOptions"
                        :removable="!isValidated('prices')"
                        :disabled="isValidated('prices')"
                        :errors="priceErrors[index]"
                        @update:model-value="(v) => prices[index] = v"
                        @remove="askRemovePrice(index)"
                    />
                    <div v-if="!isValidated('prices')" class="flex justify-center gap-6">
                        <MalioButton
                            variant="secondary"
                            icon-name="mdi:add-bold"
                            icon-position="left"
                            :label="t('transport.carriers.form.price.add')"
                            :disabled="!canAddPrice"
                            @click="addPrice"
                        />
                        <MalioButton
                            variant="primary"
                            :label="t('transport.carriers.form.submit')"
                            :disabled="tabSubmitting || carrierId === null"
                            @click="onSubmitPrices"
                        />
                    </div>
                </div>
            </template>

            <!-- Plus d'onglet placeholder : tous les onglets ont leur contenu. -->
            <template
                v-for="key in placeholderTabs"
                :key="key"
                #[key]
            >
                <div class="mt-12 flex justify-center text-m-muted">
                    {{ t('transport.carriers.form.comingSoon') }}
                </div>
            </template>
        </MalioTabList>

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

<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue'
import { extractApiErrorMessage } from '~/shared/utils/api'
import { isRowRemovable } from '~/shared/utils/collectionRow'
import CarrierAddressBlock from '~/modules/transport/components/CarrierAddressBlock.vue'
import CarrierContactBlock from '~/modules/transport/components/CarrierContactBlock.vue'
import CarrierPriceBlock from '~/modules/transport/components/CarrierPriceBlock.vue'
import CarrierQualimatTab from '~/modules/transport/components/CarrierQualimatTab.vue'
import { useCarrierForm } from '~/modules/transport/composables/useCarrierForm'
import type { QualimatCarrierRow } from '~/modules/transport/composables/useQualimatSearch'
import { clampPercent, LIOT_PLATES_MASK, sanitizeDecimal } from '~/modules/transport/utils/forms/numberInput'
import { FREE_TEXT_MASK } from '~/shared/utils/textSanitize'

interface SelectOption {
    value: string
    label: string
}

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

useHead({ title: t('transport.carriers.form.title') })

// Gating de la route : la creation est reservee a `manage` (Admin / Bureau).
// Commerciale (consultation seule), Compta et Usine sont rediriges vers le repertoire.
if (!can('transport.carriers.manage')) {
    await navigateTo('/carriers')
}

const {
    main,
    carrierId,
    mainLocked,
    mainSubmitting,
    tabSubmitting,
    mainErrors,
    dischargeUploading,
    selectDischarge,
    clearDischarge,
    isLiot,
    isQualimat,
    certificationReadonly,
    showCharteredFields,
    showDischarge,
    tabKeys,
    activeTab,
    unlockedIndex,
    isValidated,
    address,
    addressErrors,
    submitAddress,
    contacts,
    contactErrors,
    canAddContact,
    addContact,
    removeContact,
    submitContacts,
    prices,
    priceErrors,
    canAddPrice,
    addPrice,
    removePrice,
    submitPrices,
    submitMain,
    applyQualimatSelection,
} = useCarrierForm()

// Nom de fichier affiché dans le champ Décharge (alimenté à la sélection).
const dischargeFileName = ref('')

/** Vidage du champ Décharge : oublie le fichier en attente / l'IRI + le nom affiché. */
function onClearDischarge(): void {
    clearDischarge()
    dischargeFileName.value = ''
}

// Certifications selectionnables manuellement (spec § Formulaire principal) :
// GMP+ / OVOCOM / Compte-propre / Autre. QUALIMAT n'y figure PAS — il est posé par
// la saisie assistee (onglet Qualimat). On l'ajoute cependant aux options QUAND il
// est deja selectionne (transporteur QUALIMAT integre), uniquement pour AFFICHER
// son libelle dans le select en lecture seule.
const SELECTABLE_CERTIFICATIONS = ['GMP_PLUS', 'OVOCOM', 'COMPTE_PROPRE', 'AUTRE'] as const

const certificationOptions = computed<SelectOption[]>(() => {
    const codes: string[] = [...SELECTABLE_CERTIFICATIONS]
    if (main.certificationType === 'QUALIMAT') {
        codes.unshift('QUALIMAT')
    }
    return codes.map(code => ({
        value: code,
        label: t(`transport.carriers.certification.${code}`),
    }))
})

// Icone (Iconify) affichee dans chaque onglet, par cle.
const TAB_ICONS: Record<string, string> = {
    qualimat: 'mdi:truck-fast-outline',
    addresses: 'mdi:map-marker-outline',
    contacts: 'mdi:account-box-plus-outline',
    prices: 'mdi:payment',
}

// Onglets desactives tant que le formulaire principal n'est pas valide
// (unlockedIndex = -1 au depart) ; deverrouillage progressif ensuite.
const tabs = computed(() => tabKeys.value.map((key, index) => ({
    key,
    label: t(`transport.carriers.tab.${key}`),
    icon: TAB_ICONS[key],
    disabled: index > unlockedIndex.value,
})))

// Tous les onglets ont désormais leur contenu (qualimat / addresses / contacts / prices).
const placeholderTabs = computed(() => tabKeys.value.filter(
    key => key !== 'qualimat' && key !== 'addresses' && key !== 'contacts' && key !== 'prices',
))

// ── Référentiels de l'onglet Prix (clients / fournisseurs / sites) ───────────
const clientOptions = ref<SelectOption[]>([])
const supplierOptions = ref<SelectOption[]>([])
const siteOptions = ref<SelectOption[]>([])

/** Charge un référentiel paginé (?pagination=false) et mappe en options { IRI, libellé }. */
async function loadOptions(
    url: string,
    target: typeof clientOptions,
    labelOf: (m: Record<string, unknown>) => string,
): Promise<void> {
    try {
        const data = await api.get<{ member?: Record<string, unknown>[] }>(
            url,
            { pagination: 'false' },
            { headers: { Accept: 'application/ld+json' }, toast: false },
        )
        target.value = (data.member ?? []).map(m => ({ value: String(m['@id']), label: labelOf(m) }))
    }
    catch {
        target.value = []
    }
}

/** Charge les référentiels de l'onglet Prix (non bloquant : selects vides si échec). */
function loadPriceReferentials(): void {
    void loadOptions('/clients', clientOptions, m => String(m.companyName ?? m['@id']))
    void loadOptions('/suppliers', supplierOptions, m => String(m.companyName ?? m['@id']))
    void loadOptions('/sites', siteOptions, m => String(m.name ?? m['@id']))
}

// ── Onglet Adresses (ERP-167) ────────────────────────────────────────────────
// Pays : France garantie en tete meme si /countries echoue (resilience), pour
// rester preselectionnable par defaut sur chaque adresse (RG-4.05).
const countryOptions = ref<SelectOption[]>([{ value: 'France', label: 'France' }])

/** Charge le referentiel pays (/api/countries) ; conserve France par defaut si echec. */
async function loadCountries(): Promise<void> {
    try {
        const data = await api.get<{ member?: { name: string }[] }>(
            '/countries',
            { pagination: 'false' },
            { headers: { Accept: 'application/ld+json' }, toast: false },
        )
        const list = (data.member ?? []).map(c => ({ value: c.name, label: c.name }))
        countryOptions.value = list.some(c => c.value === 'France')
            ? list
            : [{ value: 'France', label: 'France' }, ...list]
    }
    catch {
        // Reste sur le fallback France (non bloquant).
    }
}

onMounted(() => {
    loadCountries().catch(() => {})
    loadPriceReferentials()
})

// Avertissement unique quand l'autocompletion d'adresse bascule en degrade.
const addressDegradedNotified = ref(false)

function onAddressDegraded(): void {
    if (addressDegradedNotified.value) {
        return
    }
    addressDegradedNotified.value = true
    toast.warning({
        title: t('transport.carriers.toast.error'),
        message: t('transport.carriers.form.address.degraded'),
    })
}

/** Message d'erreur affichable (toast) extrait d'une erreur API — jamais undefined. */
function apiErrorMessage(error: unknown): string {
    const data = (error as { response?: { _data?: unknown } })?.response?._data
    return extractApiErrorMessage(data) || t('transport.carriers.toast.error')
}

/** Valide l'onglet Adresses (POST/PATCH par ligne ; avance gere par le composable). */
async function onSubmitAddresses(): Promise<void> {
    const ok = await submitAddress(error => toast.error({
        title: t('transport.carriers.toast.error'),
        message: apiErrorMessage(error),
    }))
    if (ok) {
        toast.success({ title: t('transport.carriers.toast.addressSaved') })
    }
}

// Modal de confirmation de suppression (générique : bloc contact OU prix).
const deleteConfirm = reactive({ open: false, action: null as null | (() => void) })

/** Valide l'onglet Contacts (POST/PATCH par ligne ; avance gérée par le composable). */
async function onSubmitContacts(): Promise<void> {
    const ok = await submitContacts(error => toast.error({
        title: t('transport.carriers.toast.error'),
        message: apiErrorMessage(error),
    }))
    if (ok) {
        toast.success({ title: t('transport.carriers.toast.contactSaved') })
    }
}

function askRemoveContact(index: number): void {
    deleteConfirm.action = () => { void removeContact(index) }
    deleteConfirm.open = true
}

/**
 * Valide l'onglet Prix = DERNIER onglet du flux de création. Au succès, l'ajout est
 * terminé : toast final + retour au répertoire transporteurs (aligné sur M1/M2/M3).
 */
async function onSubmitPrices(): Promise<void> {
    const ok = await submitPrices(error => toast.error({
        title: t('transport.carriers.toast.error'),
        message: apiErrorMessage(error),
    }))
    if (ok) {
        toast.success({ title: t('transport.carriers.toast.priceSaved') })
        await navigateTo('/carriers')
    }
}

function askRemovePrice(index: number): void {
    deleteConfirm.action = () => { void removePrice(index) }
    deleteConfirm.open = true
}

function runDeleteConfirm(): void {
    deleteConfirm.action?.()
    deleteConfirm.action = null
    deleteConfirm.open = false
}

/** Intégration d'une ligne QUALIMAT (émise par CarrierQualimatTab) : copie + PATCH
 *  (cf. useCarrierForm.applyQualimatSelection). */
async function onIntegrateQualimat(row: QualimatCarrierRow): Promise<void> {
    const ok = await applyQualimatSelection(row)
    if (ok) {
        toast.success({ title: t('transport.carriers.toast.integrateSuccess') })
    }
}

// Indexation plafonnée à 100 % : la clé force le ré-affichage du MalioInputAmount
// (contrôlé) quand le plafonnement laisse le modelValue inchangé.
const indexationKey = ref(0)

/** Saisie de l'indexation : plafonne à 100 et re-synchronise le champ si plafonné. */
function onIndexationInput(value: string): void {
    const clamped = clampPercent(value)
    main.indexationRate = clamped
    if (clamped !== value) {
        indexationKey.value += 1
    }
}

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

/**
 * Valide le formulaire principal (POST /carriers ; bascule geree par le composable).
 * RG-4.07 : pour un transporteur QUALIMAT, l'adresse copiee est persistee
 * automatiquement (pas de bouton Valider dans l'onglet Adresses).
 */
async function onSubmitMain(): Promise<void> {
    const ok = await submitMain()
    if (ok && isQualimat.value) {
        await submitAddress(error => toast.error({
            title: t('transport.carriers.toast.error'),
            message: apiErrorMessage(error),
        }))
    }
}
</script>
