import { computed, reactive, ref } from 'vue'
import { useFormErrors } from '~/shared/composables/useFormErrors'
import {
    emptyCarrierAddressCopy,
    emptyCarrierMain,
    type CarrierAddressCopy,
    type CarrierMainDraft,
    type CarrierMainResponse,
} from '~/modules/transport/types/carrierForm'
import type { QualimatCarrierRow } from '~/modules/transport/composables/useQualimatSearch'

/** Nom du cas spécial « compte-propre » LIOT (comparaison insensible à la casse, RG-4.01). */
const LIOT_NAME = 'LIOT'

/**
 * Workflow de l'écran « Ajouter un transporteur » (M4 Transport, ERP-165) —
 * miroir conceptuel de `useSupplierForm` (M2) / `useProviderForm` (M3).
 *
 * Périmètre ERP-165 : le formulaire PRINCIPAL (pré-onglets) et l'orchestration de
 * la barre d'onglets. La création est INCRÉMENTALE (spec-front § Écran Ajouter) :
 *  - on POST d'abord le formulaire principal (`POST /api/carriers`) ;
 *  - au succès le bloc principal passe en lecture seule, le 1er onglet (Qualimat)
 *    se déverrouille et devient actif ;
 *  - chaque onglet validé déverrouille le suivant (PATCH partiels par groupe de
 *    sérialisation) et passe en lecture seule.
 *
 * Les champs conditionnels du formulaire principal (indexation / benne / volume
 * si affrété, décharge si AUTRE, cas LIOT) et la saisie assistée QUALIMAT arrivent
 * à ERP-166 ; le contenu des onglets Adresses / Contacts / Prix aux tickets
 * suivants. Ce composable pose le POST principal, le PATCH partiel et le gating
 * des onglets.
 *
 * État 100 % local à l'instance (refs / reactive) — aucune persistance URL.
 */

/**
 * Clés des onglets du flux de création, dans l'ordre de la barre (spec-front
 * § Écran Ajouter). Toujours les 4 (pas de gating par permission au M4, ≠ l'onglet
 * Comptabilité du M3).
 */
export const CARRIER_TAB_KEYS = ['qualimat', 'addresses', 'contacts', 'prices'] as const

export function useCarrierForm() {
    const api = useApi()
    const { t } = useI18n()
    const toast = useToast()

    // Erreurs de validation par champ (ERP-101) du formulaire principal.
    const mainErrors = useFormErrors()

    // ── État du transporteur créé ─────────────────────────────────────────────
    const carrierId = ref<number | null>(null)
    const mainLocked = ref(false)
    const mainSubmitting = ref(false)

    // ── Formulaire principal ──────────────────────────────────────────────────
    const main = reactive<CarrierMainDraft>(emptyCarrierMain())

    // Adresse copiée depuis QUALIMAT à la sélection (alimente l'onglet Adresses,
    // ticket ultérieur). Vide tant qu'aucun transporteur QUALIMAT n'est intégré.
    const qualimatAddress = ref<CarrierAddressCopy>(emptyCarrierAddressCopy())

    // ── Affichage conditionnel du formulaire principal (RG-4.01 / 4.02 / 4.03) ──
    // Cas LIOT : nom == « LIOT » → seul `liotPlates` est pertinent, le reste masqué.
    const isLiot = computed(() => main.name.trim().toUpperCase() === LIOT_NAME)
    // Transporteur QUALIMAT : la FK est posée → certification figée à « QUALIMAT ».
    const isQualimat = computed(() => main.qualimatCarrierIri !== null)
    // Certification masquée en cas LIOT ; lecture seule si QUALIMAT (ou bloc verrouillé).
    const showCertification = computed(() => !isLiot.value)
    const certificationReadonly = computed(() => isQualimat.value || mainLocked.value)
    // RG-4.03 : champs d'affrètement (indexation / contenant / volume) visibles et
    // obligatoires si « Affréter » coché — masqués en cas LIOT.
    const showCharteredFields = computed(() => main.isChartered && !isLiot.value)
    // RG-4.02 : décharge visible et obligatoire si certification == AUTRE (hors LIOT).
    const showDischarge = computed(() => main.certificationType === 'AUTRE' && !isLiot.value)

    // ── Onglets : ordre + gating progressif ───────────────────────────────────
    const tabKeys = ref<string[]>([...CARRIER_TAB_KEYS])
    // Index du dernier onglet déverrouillé (-1 tant que le transporteur n'est pas créé).
    const unlockedIndex = ref(-1)
    const activeTab = ref<string>(CARRIER_TAB_KEYS[0])
    // Onglets validés (passent en lecture seule).
    const validated = reactive<Record<string, boolean>>({})
    // Mode MODIFICATION (ticket ultérieur) : navigation libre, pas de verrouillage
    // ni de bascule automatique d'onglet à la validation (cf. completeTab).
    const editMode = ref(false)

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

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

    /**
     * Validation FRONT du formulaire principal : seul le nom est requis côté front
     * (RG-4.01). Le back reste la couche autoritaire (ERP-101) — la certification
     * obligatoire (sauf LIOT) et les RG conditionnelles sont re-validées serveur et
     * remontées en 422 inline, sans pré-check front (qui devrait connaître le cas
     * LIOT, hors périmètre ERP-165).
     */
    function validateMainFront(): boolean {
        let valid = true
        if (!main.name?.trim()) {
            mainErrors.setError('name', t('transport.carriers.form.errors.nameRequired'))
            valid = false
        }
        return valid
    }

    /**
     * Payload du POST principal (groupe `carrier:write:main`). `name` et
     * `certificationType` sont omis s'ils sont vides afin que la 422 porte la
     * violation métier (NotBlank sur le nom, « certification obligatoire » sur la
     * certification) sur le champ plutôt qu'une erreur de type.
     */
    function buildMainPayload(): Record<string, unknown> {
        // Cas LIOT (RG-4.01) : seul `liotPlates` est pertinent ; les autres champs
        // sont masqués côté front et non envoyés (le back stocke ce qu'il reçoit).
        if (isLiot.value) {
            const payload: Record<string, unknown> = { name: main.name, isChartered: false }
            if (main.liotPlates.trim()) {
                payload.liotPlates = main.liotPlates
            }
            return payload
        }

        const payload: Record<string, unknown> = { isChartered: main.isChartered }
        if (main.name.trim()) {
            payload.name = main.name
        }
        if (main.certificationType) {
            payload.certificationType = main.certificationType
        }
        // FK QUALIMAT (saisie assistée, § 2.5) envoyée si une ligne a été intégrée.
        if (main.qualimatCarrierIri) {
            payload.qualimatCarrier = main.qualimatCarrierIri
        }
        // RG-4.02 : décharge envoyée seulement en certification AUTRE ; omise quand
        // absente pour que la 422 « obligatoire » porte sur le champ.
        if (main.certificationType === 'AUTRE' && main.dischargeDocumentIri) {
            payload.dischargeDocument = main.dischargeDocumentIri
        }
        // RG-4.03 : indexation / contenant / volume envoyés seulement si affrété ;
        // omis quand vides pour déclencher la 422 NotBlank inline sur le champ.
        if (main.isChartered) {
            if (main.indexationRate.trim()) {
                payload.indexationRate = main.indexationRate
            }
            if (main.containerType) {
                payload.containerType = main.containerType
            }
            if (main.volumeM3.trim()) {
                payload.volumeM3 = main.volumeM3
            }
        }
        return payload
    }

    /**
     * POST /carriers (groupe `carrier:write:main`). Pré-check front (nom), puis
     * création. Au succès : verrouille le bloc principal, déverrouille le 1er onglet
     * et bascule sur « Qualimat ». Retourne true si créé, false sinon.
     */
    async function submitMain(): Promise<boolean> {
        if (mainSubmitting.value) return false
        mainErrors.clearErrors()
        if (!validateMainFront()) return false

        mainSubmitting.value = true
        try {
            const created = await api.post<CarrierMainResponse>('/carriers', buildMainPayload(), {
                headers: { Accept: 'application/ld+json' },
                toast: false,
            })

            carrierId.value = created.id
            // Réaffiche les valeurs normalisées renvoyées par le serveur (nom en
            // UPPERCASE — RG-4.13 ; certification éventuellement forcée).
            main.name = created.name ?? main.name
            main.certificationType = created.certificationType ?? main.certificationType

            mainLocked.value = true
            unlockedIndex.value = 0
            activeTab.value = tabKeys.value[0] ?? CARRIER_TAB_KEYS[0]
            toast.success({ title: t('transport.carriers.toast.createSuccess') })
            return true
        }
        catch (error) {
            // 409 = doublon de nom (RG-4.12) → erreur inline dédiée + 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('transport.carriers.form.duplicateName')
                mainErrors.setError('name', message)
                toast.error({ title: t('transport.carriers.toast.error'), message })
            }
            else {
                mainErrors.handleApiError(error, { fallbackMessage: t('transport.carriers.toast.error') })
            }
            return false
        }
        finally {
            mainSubmitting.value = false
        }
    }

    /**
     * PATCH partiel du transporteur (mode strict : un seul groupe de sérialisation
     * par appel — spec-back § 2.9). Servira les onglets à champs scalaires des
     * tickets suivants. No-op tant que le transporteur n'existe pas.
     */
    async function patchCarrier(payload: Record<string, unknown>): Promise<void> {
        if (carrierId.value === null) return
        await api.patch(`/carriers/${carrierId.value}`, payload, { toast: false })
    }

    /**
     * Intègre une ligne QUALIMAT sélectionnée dans l'onglet Qualimat (RG-4.01 /
     * § 2.5) : copie le nom, force la certification à « QUALIMAT » (lecture seule),
     * pose la FK `qualimatCarrier` (IRI) et copie l'adresse (pour l'onglet Adresses).
     * Si le transporteur existe déjà (post-POST, cas nominal de l'onglet), persiste
     * la copie via un PATCH partiel `carrier:write:main`. La copie locale a lieu
     * dans tous les cas. Retourne true si l'intégration a abouti.
     */
    async function applyQualimatSelection(row: QualimatCarrierRow): Promise<boolean> {
        main.name = row.name ?? ''
        main.certificationType = 'QUALIMAT'
        main.qualimatCarrierIri = row['@id']
        qualimatAddress.value = {
            country: 'France',
            postalCode: row.postalCode ?? '',
            city: row.city ?? '',
            street: row.address ?? '',
        }

        if (carrierId.value === null) {
            return true
        }

        try {
            await patchCarrier({
                qualimatCarrier: row['@id'],
                name: row.name,
                certificationType: 'QUALIMAT',
            })
            return true
        }
        catch (error) {
            mainErrors.handleApiError(error, { fallbackMessage: t('transport.carriers.toast.error') })
            return false
        }
    }

    /**
     * Marque un onglet validé (passe en lecture seule), déverrouille et avance à
     * l'onglet suivant. Retourne true si c'était le dernier onglet du flux (création
     * terminée), false sinon.
     */
    function completeTab(key: string): boolean {
        // En modification : navigation libre, l'onglet reste éditable après validation.
        if (editMode.value) {
            return false
        }
        validated[key] = true
        const index = tabIndex(key)
        const next = tabKeys.value[index + 1]
        if (next === undefined) {
            return true
        }
        unlockedIndex.value = Math.max(unlockedIndex.value, index + 1)
        activeTab.value = next
        return false
    }

    return {
        // état
        main,
        qualimatAddress,
        carrierId,
        mainLocked,
        mainSubmitting,
        mainErrors,
        // affichage conditionnel
        isLiot,
        isQualimat,
        showCertification,
        certificationReadonly,
        showCharteredFields,
        showDischarge,
        // onglets
        tabKeys,
        activeTab,
        unlockedIndex,
        validated,
        editMode,
        isValidated,
        // actions
        validateMainFront,
        buildMainPayload,
        submitMain,
        patchCarrier,
        applyQualimatSelection,
        completeTab,
    }
}
