<template>
    <form>
        <div class="flex flex-col">
            <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"
                    option-label-class="uppercase"
                    wrapper-class="w-full uppercase"
                    group-class="grid grid-cols-[336px_336px_355px_200px] w-[160px_160px_200px_180px] mt-9 mb-7"
                    :disabled="!isAdmin"
                />
            </div>

            <div class="w-full grid grid-cols-[3fr_1fr] gap-12 col-start-2 row-start-1">
                <div
                    v-if="selectedMerchandiseTypeId && !isGranule"
                    class="flex gap-[218px]"
                >
                    <div
                        v-for="building in buildings"
                        :key="building.id"
                    >
                        <UiCheckbox
                            v-model="selectedBuildingIds"
                            :value="String(building.id)"
                            :label="building.label"
                            :disabled="!isAdmin"
                            input-class="accent-primary-700 focus:ring-primary-700"
                            label-class="text-xl uppercase"
                        />
                    </div>
                </div>

                <div
                    v-if="selectedMerchandiseTypeId && isAutres"
                    class="flex flex-col justify-self-end max-w-[182px]"
                >
                    <UiTextInput
                        id="merchandise-detail"
                        :disabled="!isAdmin"
                        v-model="merchandiseDetail"
                        placeholder="Préciser"
                        :maxlength="255"
                        class="h-6"
                    />
                </div>
            </div>

            <div
                v-if="selectedMerchandiseTypeId && 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 text-lg"
                        >
                            <UiCheckbox
                                v-model="selectedPelletBuildingIds[String(type.id)]"
                                :value="String(building.id)"
                                :label="building.label"
                                :disabled="!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 type { BuildingData } from '~/services/dto/building-data'
import type { MerchandiseTypeData } from '~/services/dto/merchandise-type-data'
import type { PelletTypeData } from '~/services/dto/pellet-type-data'
import type { MerchandiseEntryData } from '~/services/dto/reception-data'
import { getBuildingList } from '~/services/building'
import { getMerchandiseTypeList } from '~/services/merchandise-type'
import { getPelletTypeList } from '~/services/pellet-type'
import { MERCHANDISE_TYPE_CODES } from '~/utils/constants'

const props = defineProps<{
    modelValue: MerchandiseEntryData
    isAdmin: boolean
}>()

const emit = defineEmits<{
    (event: 'update:modelValue', value: MerchandiseEntryData): void
}>()

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 isHydrating = ref(false)
const isReady = ref(false)

const selectedMerchandiseType = computed(() =>
    merchandiseTypes.value.find((type) => String(type.id) === selectedMerchandiseTypeId.value) ?? null
)
const isGranule = computed(
    () => selectedMerchandiseType.value?.code === MERCHANDISE_TYPE_CODES.GRANULE
)
const isAutres = computed(
    () => selectedMerchandiseType.value?.code === MERCHANDISE_TYPE_CODES.AUTRES
)

function clonePelletSelections(value: Record<string, string[]>) {
    const clone: Record<string, string[]> = {}
    for (const [key, buildingIds] of Object.entries(value)) {
        clone[key] = [...buildingIds]
    }
    return clone
}

function ensurePelletKeys() {
    for (const pelletType of pelletTypes.value) {
        const key = String(pelletType.id)
        if (!selectedPelletBuildingIds.value[key]) {
            selectedPelletBuildingIds.value[key] = []
        }
    }
}

function hydrateFromModelValue(value: MerchandiseEntryData) {
    isHydrating.value = true
    try {
        selectedMerchandiseTypeId.value = value.merchandiseTypeId ?? ''
        merchandiseDetail.value = value.merchandiseDetail ?? ''
        selectedBuildingIds.value = [...(value.selectedBuildingIds ?? [])]
        selectedPelletBuildingIds.value = clonePelletSelections(
            value.selectedPelletBuildingIds ?? {}
        )
        ensurePelletKeys()
    } finally {
        isHydrating.value = false
    }
}

function emitModelValue() {
    emit('update:modelValue', {
        merchandiseTypeId: selectedMerchandiseTypeId.value,
        merchandiseDetail: merchandiseDetail.value,
        selectedBuildingIds: [...selectedBuildingIds.value],
        selectedPelletBuildingIds: clonePelletSelections(selectedPelletBuildingIds.value)
    })
}

watch(
    () => props.modelValue,
    (value) => {
        hydrateFromModelValue(value)
    },
    { deep: true }
)

watch(
    [selectedMerchandiseTypeId, selectedBuildingIds, selectedPelletBuildingIds, merchandiseDetail],
    () => {
        if (isHydrating.value || !isReady.value) {
            return
        }

        if (isGranule.value) {
            if (selectedBuildingIds.value.length > 0) {
                selectedBuildingIds.value = []
            }
        } else {
            for (const key of Object.keys(selectedPelletBuildingIds.value)) {
                if (selectedPelletBuildingIds.value[key].length > 0) {
                    selectedPelletBuildingIds.value[key] = []
                }
            }
        }

        if (!isAutres.value && merchandiseDetail.value !== '') {
            merchandiseDetail.value = ''
        }

        emitModelValue()
    },
    { deep: true }
)

onMounted(async () => {
    const [merchandiseTypeList, buildingList, pelletTypeList] = await Promise.all([
        getMerchandiseTypeList(),
        getBuildingList(),
        getPelletTypeList()
    ])
    merchandiseTypes.value = merchandiseTypeList
    buildings.value = buildingList
    pelletTypes.value = pelletTypeList

    hydrateFromModelValue(props.modelValue)
    isReady.value = true
    emitModelValue()
})
</script>
