<template>
    <form>
            <div
                class="flex flex-col w-full">
                <div class="w-full col-start-1 row-start-1">
                <UiRadioGroup
                    id="merchandise-type"
                    v-model="selectedMerchandiseTypeId"
                    label="Type de marchandises"
                    :options="merchandiseTypes.map((type) => ({
                        value: String(type.id),
                        label: type.label
                    }))"
                    input-class="accent-primary-700 focus:ring-primary-700"
                    item-class="text-primary-700/50 [&:has(input:checked)]:text-primary-700"
                    option-label-class="uppercase"
                    wrapper-class="w-full uppercase "
                    group-class="grid grid-cols-[335px_337px_355px_200px] w-[160px_160px_200px_200px] mt-9 mb-7"
                    :disabled="!auth.isAdmin"
                />
                </div>

                <div class=" w-full grid grid-cols-[3fr_1fr] gap-[80px] col-start-2 row-start-1 ">
                <div
                    v-if="merchandiseTypeId && !isGranule"
                    class="flex gap-[187px]"
                >
                    <div
                        v-for="building in buildings"
                        :key="building.id"
                    >
                        <UiCheckbox
                            v-model="selectedBuildingIds"
                            :value="String(building.id)"
                            :label="building.label"
                            :disabled="!auth.isAdmin"
                            input-class="accent-primary-700 focus:ring-primary-700"
                            label-class="text-xl uppercase"
                        />
                    </div>
                </div>
                <div
                    v-if="merchandiseTypeId && isAutres"
                    class="flex flex-col w-full max-w-[225px]"
                >
                    <UiTextInput
                        id="merchandise-detail"
                        :disabled="!auth.isAdmin"
                        v-model="merchandiseDetail"
                        placeholder="Préciser"
                        :maxlength="255"
                    />
                </div>
                </div>

                <div
                    v-if="merchandiseTypeId && isGranule"
                    class="flex flex-col gap-10 w-full col-start-2 row-start-1 "
                >
                    <div class="grid grid-cols-1 md:grid-cols-[max-content_max-content_max-content_max-content] justify-between">

                    <div v-for="type in pelletTypes" :key="type.id" class="flex flex-col gap-4">
                            <p class="mb-1 font-medium uppercase">{{ type.label }}</p>
                            <div
                                v-for="building in buildings"
                                :key="building.id"
                                class="flex items-center text-lg"
                            >
                                <UiCheckbox
                                    v-model="selectedPelletBuildingIds[String(type.id)]"
                                    :value="String(building.id)"
                                    :label="building.label"
                                    :disabled="!auth.isAdmin"
                                    input-class="accent-primary-700 focus:ring-primary-700"
                                    label-class="text-lg"
                                />
                            </div>
                        </div>
                    </div>
                </div>
            </div>
    </form>
</template>

<script setup lang="ts">
import {computed, onMounted, ref, watch} from 'vue'
import {getBuildingList} from '~/services/building'
import {getMerchandiseTypeList} from '~/services/merchandise-type'
import type {MerchandiseTypeData} from '~/services/dto/merchandise-type-data'
import type {BuildingData} from '~/services/dto/building-data'
import type {PelletTypeData} from '~/services/dto/pellet-type-data'
import {getPelletTypeList} from '~/services/pellet-type'
import {
    createReceptionPelletBuilding,
    deleteReceptionPelletBuilding,
    getReceptionPelletBuildingList
} from '~/services/reception-pellet-building'
import {MERCHANDISE_TYPE_CODES} from '~/utils/constants'
import {getReception, updateReception} from "~/services/reception";

const merchandiseTypes = ref<MerchandiseTypeData[]>([])
const buildings = ref<BuildingData[]>([])
const pelletTypes = ref<PelletTypeData[]>([])
const selectedMerchandiseTypeId = ref('')
const selectedBuildingIds = ref<string[]>([])
const selectedPelletBuildingIds = ref<Record<string, string[]>>({})
const merchandiseDetail = ref('')
const auth = useAuthStore()
const initialMerchandiseTypeId = ref<string | null>(null)
const initialMerchandiseDetail = ref<string | null>(null)
const initialBuildingIds = ref<string[]>([])
const initialPelletSelections = ref<Record<string, string[]>>({})
const props = defineProps<{
    idReception: number
    isValidate: boolean
}>()
const receptionId = props.idReception
const reception = await getReception(receptionId)
const merchandiseTypeId = reception.receptionType?.id

// Extrait l'ID d'une relation depuis un IRI ou un objet complet.
const getRelationId = (value: unknown): string | null => {
    if (!value) {
        return null
    }

    if (typeof value === 'string') {
        const match = value.match(/\/(\d+)$/)
        return match ? match[1] : null
    }

    if (typeof value === 'object' && 'id' in value) {
        const record = value as { id?: number | string }
        if (typeof record.id === 'number') {
            return String(record.id)
        }
        if (typeof record.id === 'string') {
            return record.id
        }
    }

    return null
}

// Type de marchandise sélectionné dans le select
const selectedMerchandiseType = computed(() =>
    merchandiseTypes.value.find((type) => String(type.id) === selectedMerchandiseTypeId.value)
)
// Indique si le type est "Granulé"
const isGranule = computed(() => selectedMerchandiseType.value?.code === MERCHANDISE_TYPE_CODES.GRANULE)
// Indique si le type est "Autres"
const isAutres = computed(() => selectedMerchandiseType.value?.code === MERCHANDISE_TYPE_CODES.AUTRES)

const hasMerchandiseChanged = () => {
    const currentTypeId = selectedMerchandiseTypeId.value || null
    if (initialMerchandiseTypeId.value !== currentTypeId) {
        return true
    }

    const currentDetail = isAutres.value ? merchandiseDetail.value.trim() : ''
    if ((initialMerchandiseDetail.value ?? '') !== currentDetail) {
        return true
    }

    const currentBuildings = isGranule.value ? [] : [...selectedBuildingIds.value].sort()
    const initialBuildings = [...initialBuildingIds.value].sort()
    if (currentBuildings.length !== initialBuildings.length) {
        return true
    }
    for (let i = 0; i < currentBuildings.length; i += 1) {
        if (currentBuildings[i] !== initialBuildings[i]) {
            return true
        }
    }

    const currentPellets = normalizePelletSelections(selectedPelletBuildingIds.value)
    const initialPellets = normalizePelletSelections(initialPelletSelections.value)
    if (currentPellets.length !== initialPellets.length) {
        return true
    }
    for (let i = 0; i < currentPellets.length; i += 1) {
        if (currentPellets[i] !== initialPellets[i]) {
            return true
        }
    }

    return false
}

const normalizePelletSelections = (selections: Record<string, string[]>) => {
    const pairs: string[] = []
    for (const [pelletTypeId, buildingIds] of Object.entries(selections)) {
        for (const buildingId of buildingIds) {
            pairs.push(`${pelletTypeId}:${buildingId}`)
        }
    }
    return pairs.sort()
}

// Charge les référentiels et hydrate le formulaire depuis la réception
onMounted(async () => {
    const [merchandiseTypeList, buildingList, pelletTypeList] = await Promise.all([
        getMerchandiseTypeList(),
        getBuildingList(),
        getPelletTypeList()
    ])
    merchandiseTypes.value = merchandiseTypeList
    buildings.value = buildingList
    pelletTypes.value = pelletTypeList

    const currentId = reception.merchandiseType?.id
    if (currentId) {
        selectedMerchandiseTypeId.value = String(currentId)
    }
    merchandiseDetail.value = reception.merchandiseDetail ?? ''

    selectedBuildingIds.value =
        reception.buildings?.map((building) => String(building.id)) ?? []

    const existingPelletSelections = reception.pelletBuildings ?? []
    const selectionMap: Record<string, string[]> = {}
    for (const selection of existingPelletSelections) {
        // L'API peut renvoyer les relations comme IRI ou comme objets selon le contexte.
        const pelletTypeId = getRelationId(selection.pelletType)
        const buildingId = getRelationId(selection.building)
        if (!pelletTypeId || !buildingId) {
            continue
        }
        if (!selectionMap[pelletTypeId]) {
            selectionMap[pelletTypeId] = []
        }
        selectionMap[pelletTypeId].push(buildingId)
    }
    for (const pelletType of pelletTypes.value) {
        const key = String(pelletType.id)
        if (!selectionMap[key]) {
            selectionMap[key] = []
        }
    }
    selectedPelletBuildingIds.value = selectionMap
    initialMerchandiseTypeId.value = selectedMerchandiseTypeId.value || null
    initialMerchandiseDetail.value = isAutres.value ? merchandiseDetail.value.trim() : ''
    initialBuildingIds.value = [...selectedBuildingIds.value]
    initialPelletSelections.value = JSON.parse(JSON.stringify(selectedPelletBuildingIds.value))
})

watch(
    () => props.isValidate,
    async (val) => {
        if (!val) return
        await runValidate()
    }
)

const runValidate = async () => {
    if (!hasMerchandiseChanged()) {
        return
    }
    const receptionIri = `/api/receptions/${reception.id}`

    // 1) supprimer toutes les anciennes associations
    await clearPelletSelections(receptionIri)

    // 2) update reception (type + détails + buildings non-granulé)
    await updateReception(reception.id, {
        merchandiseType: selectedMerchandiseTypeId.value
            ? `/api/merchandise_types/${selectedMerchandiseTypeId.value}`
            : null,
        merchandiseDetail: isAutres.value ? merchandiseDetail.value.trim() :
            null,
        buildings: isGranule.value
            ? []
            : selectedBuildingIds.value.map((id) => `/api/buildings/${id}`),
        bovineDetail: null,
        bovinesTypes: null,
    })

    // 3) si granulé ALORS créer les nouvelles associations
    if (isGranule.value) {
        await syncPelletSelections(receptionIri)
    }

    initialMerchandiseTypeId.value = selectedMerchandiseTypeId.value || null
    initialMerchandiseDetail.value = isAutres.value ? merchandiseDetail.value.trim() : ''
    initialBuildingIds.value = [...selectedBuildingIds.value]
    initialPelletSelections.value = JSON.parse(JSON.stringify(selectedPelletBuildingIds.value))
}

// Supprime toutes les associations granulés/bâtiments existantes
async function clearPelletSelections(receptionIri: string) {
    const existing = await getReceptionPelletBuildingList(receptionIri)
    for (const selection of existing) {
        await deleteReceptionPelletBuilding(selection.id)
    }
}
// Synchronise les associations granulés/bâtiments avec l'état du formulaire
async function syncPelletSelections(receptionIri: string) {
    const existing = await getReceptionPelletBuildingList(receptionIri)
    const existingMap = new Map<string, number>()
    for (const selection of existing) {
        // Construit la table de correspondance avec des IDs normalisés pour éviter les doublons.
        const pelletTypeId = getRelationId(selection.pelletType)
        const buildingId = getRelationId(selection.building)
        if (!pelletTypeId || !buildingId) {
            continue
        }
        const key = `${pelletTypeId}:${buildingId}`
        existingMap.set(key, selection.id)
    }

    const desiredEntries: Array<{ pelletTypeId: string; buildingId: string }> = []
    for (const [pelletTypeId, buildingIds] of Object.entries(selectedPelletBuildingIds.value)) {
        for (const buildingId of buildingIds) {
            desiredEntries.push({pelletTypeId, buildingId})
        }
    }

    const desiredKeys = new Set(desiredEntries.map(
        (entry) => `${entry.pelletTypeId}:${entry.buildingId}`
    ))

    for (const [key, id] of existingMap.entries()) {
        if (!desiredKeys.has(key)) {
            await deleteReceptionPelletBuilding(id)
        }
    }

    for (const entry of desiredEntries) {
        const key = `${entry.pelletTypeId}:${entry.buildingId}`
        if (!existingMap.has(key)) {
            await createReceptionPelletBuilding({
                reception: receptionIri,
                pelletType: `/api/pellet_types/${entry.pelletTypeId}`,
                building: `/api/buildings/${entry.buildingId}`
            })
        }
    }
}

</script>
