<template>
    <!-- Adresse UNIQUE par transporteur (ERP-172) : un seul bloc, jamais supprimable. -->
    <div class="relative 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)]">
        <!-- Pays : prerempli « France » (RG-4.05). -->
        <MalioSelect
            :model-value="model.country"
            :options="countryOptions"
            :label="t('transport.carriers.form.address.country')"
            :readonly="readonly"
            :disabled="disabled"
            :required="true"
            :error="errors?.country"
            @update:model-value="(v: string | number | null) => update('country', String(v ?? 'France'))"
        />

        <!-- Code postal (RG-4.06) : declenche l'autocomplete ville (BAN). -->
        <MalioInputText
            :model-value="model.postalCode"
            :label="t('transport.carriers.form.address.postalCode')"
            :mask="POSTAL_CODE_MASK"
            :readonly="readonly"
            :disabled="disabled"
            :required="true"
            :error="errors?.postalCode"
            @update:model-value="onPostalCodeChange"
        />

        <!-- Ville : MalioSelect alimente par le code postal (BAN). Saisie libre si BAN indispo. -->
        <MalioSelect
            v-if="!degraded"
            :model-value="model.city"
            :options="cityOptions"
            :label="t('transport.carriers.form.address.city')"
            :readonly="readonly"
            :disabled="disabled"
            empty-option-label=""
            :required="true"
            :error="errors?.city"
            @update:model-value="(v: string | number | null) => update('city', v === null ? null : String(v))"
        />
        <MalioInputText
            v-else
            :model-value="model.city"
            :label="t('transport.carriers.form.address.city')"
            :mask="ADDRESS_MASK"
            :readonly="readonly"
            :disabled="disabled"
            :required="true"
            :error="errors?.city"
            @update:model-value="(v: string) => update('city', v)"
        />

        <!-- Filler : aligne le debut de la ligne suivante sur la grille. -->
        <div aria-hidden="true" />

        <!-- Adresse (BAN) sur 2 colonnes + Adresse complementaire. allow-create : le
             texte saisi est conserve si la BAN ne propose rien (saisie manuelle). -->
        <div class="col-span-2">
            <MalioInputAutocomplete
                v-if="!readonly && !disabled"
                :model-value="model.street"
                :options="addressOptions"
                :loading="addressLoading"
                :min-search-length="3"
                :label="t('transport.carriers.form.address.street')"
                :readonly="readonly"
                :disabled="disabled"
                :required="true"
                :error="errors?.street"
                :allow-create="true"
                :no-results-text="t('transport.carriers.form.address.streetNotFound')"
                @update:model-value="(v: string | number | null) => update('street', v === null ? null : String(v))"
                @search="onAddressSearch"
                @select="onAddressSelect"
            />
            <MalioInputText
                v-else
                :model-value="model.street"
                :label="t('transport.carriers.form.address.street')"
                :readonly="readonly"
                :disabled="disabled"
                :required="true"
                :error="errors?.street"
                @update:model-value="(v: string) => update('street', v)"
            />
        </div>

        <MalioInputText
            :model-value="model.streetComplement"
            :label="t('transport.carriers.form.address.streetComplement')"
            :mask="ADDRESS_MASK"
            :readonly="readonly"
            :disabled="disabled"
            :error="errors?.streetComplement"
            @update:model-value="(v: string) => update('streetComplement', v)"
        />
    </div>
</template>

<script setup lang="ts">
import { useAddressAutocomplete, type AddressSuggestion } from '~/shared/composables/useAddressAutocomplete'
import type { CarrierAddressFormDraft } from '~/modules/transport/types/carrierForm'
import { ADDRESS_MASK } from '~/shared/utils/textSanitize'

interface RefOption {
    value: string
    label: string
}

// Masque code postal FR : 5 chiffres.
const POSTAL_CODE_MASK = '#####'

const props = defineProps<{
    /** Brouillon de l'adresse (v-model). */
    modelValue: CarrierAddressFormDraft
    /** Pays disponibles (France par defaut). */
    countryOptions: RefOption[]
    readonly?: boolean
    /** Bloc desactive (champs grises, consultation — distinct de readonly). */
    disabled?: boolean
    /** Erreurs serveur 422 de cette ligne, indexees par champ (ERP-101). */
    errors?: Record<string, string>
}>()

const emit = defineEmits<{
    'update:modelValue': [value: CarrierAddressFormDraft]
    /** Emis une fois quand le service d'autocompletion bascule en indisponible. */
    'degraded': []
}>()

const { t } = useI18n()
const autocomplete = useAddressAutocomplete()

const model = computed(() => props.modelValue)

// Repli saisie libre de la VILLE quand la BAN est indisponible (recuperable).
const degraded = ref(false)
let unavailableNotified = false
const banCityOptions = ref<RefOption[]>([])
const banAddressOptions = ref<RefOption[]>([])

// Options ville effectives : on garantit que la ville courante figure toujours
// dans la liste, sinon MalioSelect afficherait un champ vide en lecture seule.
const cityOptions = computed<RefOption[]>(() => {
    const current = props.modelValue.city
    if (current && !banCityOptions.value.some(o => o.value === current)) {
        return [{ value: current, label: current }, ...banCityOptions.value]
    }
    return banCityOptions.value
})

// Meme garantie pour le champ Adresse : la rue courante doit toujours figurer
// dans les options, sinon MalioInputAutocomplete laisse le champ vide.
const addressOptions = computed<RefOption[]>(() => {
    const current = props.modelValue.street
    if (current && !banAddressOptions.value.some(o => o.value === current)) {
        return [{ value: current, label: current }, ...banAddressOptions.value]
    }
    return banAddressOptions.value
})
const addressLoading = ref(false)
// Conserve les suggestions d'adresse pour retrouver ville/CP au moment du select.
let lastAddressSuggestions: AddressSuggestion[] = []

// Filtrage des caracteres parasites : porte par le mask ADDRESS_MASK (maska) sur les
// champs texte editables (complement, ville en mode degrade). La voie en autocomplete
// (BAN) et la ville en select ne sont pas masquees (le back valide via Assert\Regex).

/** Emet un nouveau brouillon avec le champ modifie (immutabilite). */
function update<K extends keyof CarrierAddressFormDraft>(field: K, value: CarrierAddressFormDraft[K]): void {
    emit('update:modelValue', { ...props.modelValue, [field]: value })
}

/** Previent le parent (toast unique) que l'autocompletion est indisponible. */
function notifyUnavailable(): void {
    if (!unavailableNotified) {
        unavailableNotified = true
        emit('degraded')
    }
}

/** Saisie du code postal → met a jour le champ + interroge la BAN pour la ville. */
async function onPostalCodeChange(value: string): Promise<void> {
    update('postalCode', value)

    const digits = (value ?? '').replace(/\D/g, '')
    if (digits.length < 5) {
        return
    }
    try {
        const suggestions = await autocomplete.searchCity(digits)
        banCityOptions.value = suggestions.map(s => ({ value: s.city, label: s.city }))
        degraded.value = false
    }
    catch {
        degraded.value = true
        notifyUnavailable()
    }
}

/** Recherche d'adresse assistee (event de MalioInputAutocomplete). */
async function onAddressSearch(query: string): Promise<void> {
    // La BAN exige au moins 3 caracteres : on n'envoie rien en deca (evite un 400).
    if (query.trim().length < 3) {
        banAddressOptions.value = []
        return
    }
    addressLoading.value = true
    try {
        const postalCode = (model.value.postalCode ?? '').replace(/\D/g, '') || undefined
        const suggestions = await autocomplete.searchAddress(query, postalCode)
        lastAddressSuggestions = suggestions
        banAddressOptions.value = suggestions.map(s => ({ value: s.street, label: s.label }))
    }
    catch {
        // Erreur transitoire : on vide les suggestions, la prochaine frappe reessaie.
        banAddressOptions.value = []
        notifyUnavailable()
    }
    finally {
        addressLoading.value = false
    }
}

/** Selection d'une suggestion d'adresse → remplit rue + ville + CP. */
function onAddressSelect(option: { label: string, value: string | number } | null): void {
    if (option === null) {
        return
    }
    const suggestion = lastAddressSuggestions.find(s => s.street === option.value)
    if (!suggestion) {
        update('street', String(option.value))
        return
    }
    emit('update:modelValue', {
        ...props.modelValue,
        street: suggestion.street,
        city: suggestion.city,
        postalCode: suggestion.postalCode,
    })
}
</script>
