<template>
    <div class="h-full flex flex-col overflow-hidden">
        <div class="flex flex-wrap items-center justify-between gap-4">
            <h1 class="text-4xl font-bold text-primary-500">Calendrier des absences</h1>
        </div>
        <div class="flex flex-col gap-3 py-6">
            <div class="flex items-center justify-between gap-4">
                    <MalioSelectCheckbox :reserve-message-space="false"
                        v-model="selectedSiteIds"
                        :options="siteOptions"
                        label="Sites"
                        groupClass="relative z-50 w-80 h-10"
                        display-select-all
                    />
                <div class="flex gap-4">
                    <MalioButton
                        label="Ajouter"
                        icon-name="mdi:plus"
                        icon-position="left"
                        @click="openCreateFromToday"
                    />
                    <MalioButton
                        label="Imprimer"
                        variant="secondary"
                        icon-name="mdi:printer"
                        icon-position="left"
                        @click="openPrint"
                    />
                </div>
            </div>
            <div class="flex justify-between">
                <div class="flex items-center gap-4">
                    <div class="w-80">
                        <MalioInputText :reserve-message-space="false"
                            v-model="employeeFilter"
                            label="Recherche d'un employé"
                            icon-name="mdi:magnify"
                        />
                    </div>
                    <PeriodStepperPicker
                        width-class="w-[260px]"
                        :label="selectedMonthLabel"
                        picker-type="month"
                        :picker-value="monthPickerValue"
                        prev-aria-label="Mois précédent"
                        next-aria-label="Mois suivant"
                        @prev="shiftMonth(-1)"
                        @next="shiftMonth(1)"
                        @pick="onMonthPickerValue"
                    />
                </div>
            </div>
            <div class="flex flex-wrap items-center gap-6 py-2">
                <p class="font-bold">Légende :</p>
                <div v-for="type in absenceTypes" :key="type.id" class="flex items-center gap-2">
                    <div :style="{ backgroundColor: type.color }" class="h-4 w-4 rounded"></div>
                    <p>{{ type.label }}</p>
                </div>
                <div class="flex items-center gap-2">
                    <div class="h-4 w-4 rounded bg-indigo-500"></div>
                    <p>FORMATION</p>
                </div>
            </div>
        </div>

        <div class="flex-1 min-h-0">
            <CalendarGrid
                :days-in-month="daysInMonth"
                :visible-employees="visibleEmployees"
                :grid-style="gridStyle"
                :get-cell-style="getCellStyle"
                :get-cell-info="getCellInfo"
                :format-employee-name="formatEmployeeName"
                :is-holiday-date="isHolidayDate"
                @cell-click="openCreate"
                @reorder="handleReorder"
            />
        </div>

        <AbsenceFormDrawer
            v-model="isDrawerOpen"
            :employees="employees"
            :absence-types="absenceTypes"
            :form="form"
            :editing-absence="editingAbsence"
            :is-submitting="isSubmitting"
            @submit="handleSubmit"
            @delete="handleDelete"
            @cancel="closeDrawer"
        />

        <AbsencePrintDrawer
            v-model="isPrintOpen"
            :sites="sites"
            :contract-natures="contractNatureOptions"
            :work-contracts="workContractOptions"
            :print-form="printForm"
            @submit="handlePrint"
            @cancel="closePrint"
        />
    </div>
</template>

<script setup lang="ts">
import type {Employee} from '~/services/dto/employee'
import type {AbsenceType} from '~/services/dto/absence-type'
import type {Absence} from '~/services/dto/absence'
import type {HalfDay} from '~/services/dto/half-day'
import {HALF_DAYS} from '~/services/dto/half-day'
import {listEmployees, updateEmployeeOrder} from '~/services/employees'
import {listAbsenceTypes} from '~/services/absence-types'
import {createAbsence, deleteAbsence, listAbsences} from '~/services/absences'
import {listFormationsByDateRange} from '~/services/formations'
import type {Formation} from '~/services/dto/formation'
import {listPublicHolidays} from '~/services/public-holidays'
import {formatYmdToFr, getDaysInMonth, normalizeDate, parseYmd, shiftYmd, toYmd} from '~/utils/date'
import {compareEmployeesInSite, sortEmployeesBySiteAndOrder} from '~/utils/employee'
import CalendarGrid from '~/components/CalendarGrid.vue'
import AbsenceFormDrawer from '~/components/AbsenceFormDrawer.vue'
import AbsencePrintDrawer from '~/components/AbsencePrintDrawer.vue'
import PeriodStepperPicker from '~/components/PeriodStepperPicker.vue'

useHead({
    title: 'Calendrier'
})

// Données principales affichées dans la grille.
const employees = ref<Employee[]>([])
const sites = computed(() => {
    const siteMap = new Map<number, { id: number; name: string; color: string }>()
    for (const employee of employees.value) {
        if (employee.site) {
            siteMap.set(employee.site.id, employee.site)
        }
    }
    return Array.from(siteMap.values()).sort((siteA, siteB) => {
        const orderA = siteA.displayOrder ?? 0
        const orderB = siteB.displayOrder ?? 0
        if (orderA !== orderB) return orderA - orderB
        return siteA.name.localeCompare(siteB.name, 'fr')
    })
})

const siteOptions = computed(() => sites.value.map((site) => ({ label: site.name, value: site.id })))

// Filtres de sites (par défaut: tous sélectionnés à l'init).
const selectedSiteIds = ref<number[]>([])
const sitesInitialized = ref(false)

watch(sites, (next) => {
    if (sitesInitialized.value || next.length === 0) return
    selectedSiteIds.value = next.map((site) => site.id)
    sitesInitialized.value = true
}, {immediate: true})

// Tri stable: site -> nom -> prénom.
const sortedEmployees = computed(() => {
    return sortEmployeesBySiteAndOrder(employees.value)
})

// Employés visibles selon le filtre de sites.
const employeeFilter = ref('')

// Un employé est considéré "présent" sur le mois affiché si au moins une de ses
// périodes de contrat intersecte [début du mois ; fin du mois]. Sinon il est masqué.
const hasContractInSelectedMonth = (employee: Employee): boolean => {
    const monthStart = toYmd(selectedYear.value, selectedMonth.value, 1)
    const monthEnd = toYmd(selectedYear.value, selectedMonth.value + 1, 0)
    const history = employee.contractHistory ?? []
    if (history.length === 0) return false
    return history.some((period) => {
        const start = period.startDate
        const end = period.endDate ?? '9999-12-31'
        return start <= monthEnd && end >= monthStart
    })
}

const visibleEmployees = computed(() => {
    if (selectedSiteIds.value.length === 0) return []
    const filter = employeeFilter.value.trim().toLowerCase()
    return sortedEmployees.value.filter((employee) => {
        const siteOk = employee.site?.id && selectedSiteIds.value.includes(employee.site.id)
        if (!siteOk) return false
        if (!hasContractInSelectedMonth(employee)) return false
        if (!filter) return true
        const first = employee.firstName?.toLowerCase() ?? ''
        const last = employee.lastName?.toLowerCase() ?? ''
        return first.includes(filter) || last.includes(filter)
    })
})
// Données de référence et absences du mois affiché.
const absenceTypes = ref<AbsenceType[]>([])
const absences = ref<Absence[]>([])
const formations = ref<Formation[]>([])
const publicHolidays = ref<Record<string, string>>({})

// États UI.
const isDrawerOpen = ref(false)
const isSubmitting = ref(false)
const editingAbsence = ref<Absence | null>(null)
const isPrintOpen = ref(false)

// Sélecteurs de période.
const now = new Date()
const selectedMonth = ref(now.getMonth())
const selectedYear = ref(now.getFullYear())

const months = [
    {value: 0, label: 'Janvier'},
    {value: 1, label: 'Février'},
    {value: 2, label: 'Mars'},
    {value: 3, label: 'Avril'},
    {value: 4, label: 'Mai'},
    {value: 5, label: 'Juin'},
    {value: 6, label: 'Juillet'},
    {value: 7, label: 'Août'},
    {value: 8, label: 'Septembre'},
    {value: 9, label: 'Octobre'},
    {value: 10, label: 'Novembre'},
    {value: 11, label: 'Décembre'}
]

const selectedMonthLabel = computed(() => `${months[selectedMonth.value]?.label ?? ''}`)
const monthPickerValue = computed(() => `${selectedYear.value}-${String(selectedMonth.value + 1).padStart(2, '0')}`)

// Infos de calendrier calculées.
const daysInMonth = computed(() => getDaysInMonth(selectedYear.value, selectedMonth.value))
const monthStartDate = computed(() => new Date(selectedYear.value, selectedMonth.value, 1))
const monthEndDate = computed(() => new Date(selectedYear.value, selectedMonth.value + 1, 0))

// Largeur fixe de la colonne employés + une colonne par jour.
const gridStyle = computed(() => ({
    gridTemplateColumns: `160px repeat(${daysInMonth.value.length}, minmax(44px, 1fr))`
}))

// Formulaire d'absence (AM/PM par défaut = journée complète).
const form = reactive({
    employeeId: '' as number | '',
    typeId: '' as number | '',
    startDate: '',
    startHalf: 'AM' as HalfDay,
    endDate: '',
    endHalf: 'PM' as HalfDay,
    comment: ''
})

// Formulaire d'impression (intervalle + sites).
const printForm = reactive({
    from: '',
    to: '',
    siteIds: [] as number[],
    contractNatures: [] as Array<'CDI' | 'CDD' | 'INTERIM'>,
    workContractIds: [] as number[]
})

const contractNatureOptions = [
    { value: 'CDI' as const, label: 'CDI' },
    { value: 'CDD' as const, label: 'CDD' },
    { value: 'INTERIM' as const, label: 'Intérim' }
]

const workContractOptions = computed(() => {
    const byId = new Map<number, { id: number; name: string }>()
    for (const employee of employees.value) {
        const contract = employee.contract
        if (!contract?.id) continue
        byId.set(contract.id, { id: contract.id, name: contract.name })
    }
    return Array.from(byId.values()).sort((a, b) => a.name.localeCompare(b.name, 'fr'))
})

// Remet le formulaire à zéro.
const resetForm = () => {
    form.employeeId = ''
    form.typeId = ''
    form.startDate = ''
    form.startHalf = 'AM'
    form.endDate = ''
    form.endHalf = 'PM'
    form.comment = ''
}

// Ferme le drawer et nettoie l'état.
const closeDrawer = () => {
    isDrawerOpen.value = false
    editingAbsence.value = null
    resetForm()
}

// Ouvre l'impression avec la période du mois courant.
const openPrint = () => {
    const monthStart = toYmd(selectedYear.value, selectedMonth.value, 1)
    const monthEnd = toYmd(selectedYear.value, selectedMonth.value + 1, 0)
    printForm.from = monthStart
    printForm.to = monthEnd
    printForm.siteIds = [...selectedSiteIds.value]
    printForm.contractNatures = contractNatureOptions.map((item) => item.value)
    printForm.workContractIds = workContractOptions.value.map((item) => item.id)
    isPrintOpen.value = true
}

const closePrint = () => {
    isPrintOpen.value = false
}

// Détermine si la journée est une demi-journée (AM/PM) ou complète.
const getHalfForDate = (
    startDate: string,
    endDate: string,
    startHalf: HalfDay,
    endHalf: HalfDay,
    date: string
) => {
    if (startDate === endDate) {
        return startHalf === endHalf ? startHalf : null
    }
    if (date === startDate && startHalf === 'PM') return 'PM'
    if (date === endDate && endHalf === 'AM') return 'AM'
    return null
}

// Renvoie les segments occupés pour une date donnée (AM/PM).
const getSegmentsForDate = (
    startDate: string,
    endDate: string,
    startHalf: HalfDay,
    endHalf: HalfDay,
    date: string
) => {
    const half = getHalfForDate(startDate, endDate, startHalf, endHalf, date)
    if (!half) return HALF_DAYS.map((item) => item.value) as HalfDay[]
    return [half] as HalfDay[]
}

// Ajoute des mois tout en gardant un jour valide.
const addMonths = (date: Date, months: number) => {
    const next = new Date(date.getFullYear(), date.getMonth() + months, date.getDate())
    if (next.getMonth() !== (date.getMonth() + months) % 12) {
        next.setDate(0)
    }
    return next
}

const shiftMonth = (delta: number) => {
    const next = new Date(selectedYear.value, selectedMonth.value + delta, 1)
    selectedYear.value = next.getFullYear()
    selectedMonth.value = next.getMonth()
}

const onMonthPickerValue = (value: string) => {
    if (!value) return
    const [yearStr, monthStr] = value.split('-')
    const year = Number(yearStr)
    const month = Number(monthStr)
    if (!Number.isInteger(year) || !Number.isInteger(month) || month < 1 || month > 12) return
    selectedYear.value = year
    selectedMonth.value = month - 1
}

// Limite l'intervalle d'impression à 2 mois max.
const enforcePrintRange = () => {
    if (!printForm.from) return
    const start = parseYmd(printForm.from)
    if (!start) return
    const maxEnd = addMonths(start, 2)
    maxEnd.setDate(maxEnd.getDate() - 1)
    const maxEndYmd = toYmd(maxEnd.getFullYear(), maxEnd.getMonth(), maxEnd.getDate())

    if (!printForm.to) {
        printForm.to = maxEndYmd
        return
    }

    const end = parseYmd(printForm.to)
    if (!end) {
        printForm.to = maxEndYmd
        return
    }

    if (end < start) {
        printForm.to = printForm.from
        return
    }

    if (end > maxEnd) {
        printForm.to = maxEndYmd
    }
}

watch(() => printForm.from, enforcePrintRange)
watch(() => printForm.to, enforcePrintRange)

// Chargements API.
const loadEmployees = async () => {
    employees.value = await listEmployees()
}

const loadAbsenceTypes = async () => {
    absenceTypes.value = await listAbsenceTypes()
}

const loadPublicHolidays = async () => {
    publicHolidays.value = await listPublicHolidays('metropole', selectedYear.value)
}

const loadAbsences = async () => {
    const monthStart = toYmd(selectedYear.value, selectedMonth.value, 1)
    const monthEnd = toYmd(selectedYear.value, selectedMonth.value + 1, 0)
    absences.value = await listAbsences({
        from: monthStart,
        to: monthEnd,
        siteIds: selectedSiteIds.value
    })
}

const loadFormations = async () => {
    const monthStart = toYmd(selectedYear.value, selectedMonth.value, 1)
    const monthEnd = toYmd(selectedYear.value, selectedMonth.value + 1, 0)
    formations.value = await listFormationsByDateRange(monthStart, monthEnd)
}

onMounted(async () => {
    await Promise.all([loadEmployees(), loadAbsenceTypes(), loadPublicHolidays(), loadAbsences(), loadFormations()])
})

watch([selectedMonth, selectedYear, selectedSiteIds], async () => {
    await Promise.all([loadAbsences(), loadFormations()])
})

watch(selectedYear, async () => {
    await loadPublicHolidays()
})

// Indexation des absences par cellule pour eviter un find() a chaque case.
const cellAbsenceMap = computed(() => {
    const map = new Map<string, { id: number; code: string; color: string; halfLabel?: HalfDay; textColor?: string }>()
    const monthStart = monthStartDate.value
    const monthEnd = monthEndDate.value

    for (const absence of absences.value) {
        const employeeId = absence.employee?.id
        if (!employeeId) continue
        const startDate = normalizeDate(absence.startDate)
        const endDate = normalizeDate(absence.endDate)
        const start = parseYmd(startDate)
        const end = parseYmd(endDate)
        if (!start || !end) continue

        const rangeStart = start < monthStart ? monthStart : start
        const rangeEnd = end > monthEnd ? monthEnd : end
        if (rangeEnd < rangeStart) continue

        for (
            let currentDate = new Date(rangeStart.getTime());
            currentDate <= rangeEnd;
            currentDate.setDate(currentDate.getDate() + 1)
        ) {
            const dateKey = toYmd(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate())
            const key = `${employeeId}-${dateKey}`
            const halfLabel = getHalfForDate(
                startDate,
                endDate,
                absence.startHalf ?? 'AM',
                absence.endHalf ?? 'PM',
                dateKey
            ) ?? undefined
            map.set(key, {
                id: absence.id,
                code: absence.type?.code ?? '',
                color: absence.type?.color ?? '#222783',
                halfLabel
            })
        }
    }

    return map
})

// Indexation des formations par cellule pour un lookup O(1).
const cellFormationMap = computed(() => {
    const set = new Set<string>()
    const monthStart = monthStartDate.value
    const monthEnd = monthEndDate.value

    for (const formation of formations.value) {
        const employeeId = formation.employee?.id
        if (!employeeId) continue
        const startDate = normalizeDate(formation.startDate)
        const endDate = normalizeDate(formation.endDate)
        const start = parseYmd(startDate)
        const end = parseYmd(endDate)
        if (!start || !end) continue

        const rangeStart = start < monthStart ? monthStart : start
        const rangeEnd = end > monthEnd ? monthEnd : end
        if (rangeEnd < rangeStart) continue

        for (
            let currentDate = new Date(rangeStart.getTime());
            currentDate <= rangeEnd;
            currentDate.setDate(currentDate.getDate() + 1)
        ) {
            const dateKey = toYmd(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate())
            set.add(`${employeeId}-${dateKey}`)
        }
    }

    return set
})

const hasFormationOn = (employeeId: number, date: string): boolean => {
    return cellFormationMap.value.has(`${employeeId}-${date}`)
}

// Jours fériés.
const isHolidayDate = (date: string) => {
    return Boolean(publicHolidays.value[date])
}

// Renvoie l'absence effective pour une cellule (ou un "Férié" si pas d'absence).
const getCellAbsence = (employeeId: number, date: string) => {
    const absence = cellAbsenceMap.value.get(`${employeeId}-${date}`)
    if (!absence && isHolidayDate(date)) {
        return {
            id: 0,
            code: 'Férié',
            color: '#b3e5fc',
            textColor: '#0f172a'
        }
    }
    if (absence) return { ...absence, hasFormation: hasFormationOn(employeeId, date) }
    if (hasFormationOn(employeeId, date)) {
        return {
            id: 0,
            code: 'F',
            color: '#6366f1',
            textColor: '#fff',
            hasFormation: true
        }
    }
    return null
}

// Style de cellule (plein ou demi-journée).
const getCellStyle = (employeeId: number, date: string) => {
    const absence = getCellAbsence(employeeId, date)
    if (!absence) return undefined

    if (absence.halfLabel) {
        const color = absence.color
        const textColor = absence.textColor ?? '#FFF'
        const backgroundImage = absence.halfLabel === 'AM'
            ? `linear-gradient(180deg, ${color} 0 50%, transparent 50% 100%)`
            : `linear-gradient(180deg, transparent 0 50%, ${color} 50% 100%)`
        return {
            backgroundImage,
            backgroundColor: 'transparent',
            color: textColor
        }
    }

    return {
        backgroundColor: absence.color,
        color: absence.textColor ?? '#fff'
    }
}

const getCellInfo = (employeeId: number, date: string) => {
    return getCellAbsence(employeeId, date)
}

// Ouverture du drawer depuis une cellule.
const openCreate = (employee: Employee, date: string) => {
    const existing = absences.value.find((absence) => {
        const start = normalizeDate(absence.startDate)
        const end = normalizeDate(absence.endDate)
        return absence.employee?.id === employee.id && date >= start && date <= end
    })

    if (existing) {
        editingAbsence.value = existing
        form.employeeId = existing.employee.id
        form.typeId = existing.type.id
        form.startDate = normalizeDate(existing.startDate)
        form.endDate = normalizeDate(existing.endDate)
        form.startHalf = existing.startHalf ?? 'AM'
        form.endHalf = existing.endHalf ?? 'PM'
        form.comment = existing.comment ?? ''
    } else {
        editingAbsence.value = null
        form.employeeId = employee.id
        form.startDate = date
        form.endDate = date
        form.startHalf = 'AM'
        form.endHalf = 'PM'
        form.typeId = ''
        form.comment = ''
    }

    isDrawerOpen.value = true
}

// Ouverture du drawer depuis le bouton "Ajouter".
const openCreateFromToday = () => {
    editingAbsence.value = null
    form.employeeId = ''
    form.typeId = ''
    const now = new Date()
    const today = toYmd(now.getFullYear(), now.getMonth(), now.getDate())
    form.startDate = today
    form.endDate = today
    form.startHalf = 'AM'
    form.endHalf = 'PM'
    form.comment = ''
    isDrawerOpen.value = true
}

// Vérifie la présence d'un férié dans l'intervalle.
const hasHolidayInRange = (startDate: string, endDate: string) => {
    const start = parseYmd(startDate)
    const end = parseYmd(endDate)
    if (!start || !end) return false
    for (
        let currentDate = new Date(start.getTime());
        currentDate <= end;
        currentDate.setDate(currentDate.getDate() + 1)
    ) {
        const key = toYmd(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate())
        if (isHolidayDate(key)) {
            return true
        }
    }
    return false
}

// Soumission du formulaire: validations + chevauchement + save.
const handleSubmit = async () => {
    if (isSubmitting.value) return

    isSubmitting.value = true
    try {
        const start = normalizeDate(form.startDate)
        const end = normalizeDate(form.endDate)
        if (start > end) {
            window.alert("La date de fin ne peut pas etre avant la date de debut.")
            return
        }
        if (start === end && form.startHalf === 'PM' && form.endHalf === 'AM') {
            window.alert("La demi-journee de fin ne peut pas etre avant la demi-journee de debut.")
            return
        }
        if (editingAbsence.value) {
            // Modification d'une plage : une absence = une ligne par jour, sans lien en BDD.
            // On remplace donc tout le bloc contigu (même type) partant du jour cliqué par la
            // nouvelle plage : suppression de l'ancien bloc + recréation. Évite les jours
            // fantômes (raccourcissement) et les doublons (l'ancien PATCH ne nettoyait rien).
            const originalEmployeeId = editingAbsence.value.employee.id
            const newEmployeeId = Number(form.employeeId)
            const originalTypeId = editingAbsence.value.type.id
            const clickedDate = normalizeDate(editingAbsence.value.startDate)

            // Bloc contigu (vers l'avant) depuis le jour cliqué, même employé + même type d'origine.
            // On ne touche jamais aux jours antérieurs au jour cliqué.
            const sameLeaveDays = new Set(
                absences.value
                    .filter((absence) => absence.employee?.id === originalEmployeeId && absence.type?.id === originalTypeId)
                    .map((absence) => normalizeDate(absence.startDate))
            )
            const blockDates = new Set<string>()
            let cursor: string | null = clickedDate
            while (cursor && sameLeaveDays.has(cursor)) {
                blockDates.add(cursor)
                cursor = shiftYmd(cursor, 1)
            }

            // À supprimer : l'ancien bloc + toute absence recouverte par la nouvelle plage.
            const toReplace = absences.value.filter((absence) => {
                const day = normalizeDate(absence.startDate)
                const inBlock = absence.employee?.id === originalEmployeeId && blockDates.has(day)
                const inNewRange = absence.employee?.id === newEmployeeId && day >= start && day <= end
                return inBlock || inNewRange
            })

            // Confirmation uniquement si on écrase une absence d'un AUTRE type (vrai chevauchement).
            const replacesForeign = toReplace.some((absence) => absence.type?.id !== originalTypeId)
            if (replacesForeign) {
                const confirmReplace = window.confirm(
                    "Cette absence chevauche une autre. Voulez-vous la remplacer ?"
                )
                if (!confirmReplace) return
            }

            for (const absence of toReplace) {
                await deleteAbsence(absence.id)
            }
            await createAbsence({
                employeeId: newEmployeeId,
                typeId: Number(form.typeId),
                startDate: form.startDate,
                startHalf: form.startHalf,
                endDate: form.endDate,
                endHalf: form.endHalf,
                comment: form.comment
            })

            closeDrawer()
            await loadAbsences()
            return
        }

        // Création : détection de chevauchement (précision demi-journée) puis remplacement.
        const overlaps = absences.value.filter((absence) => {
            if (absence.employee?.id !== Number(form.employeeId)) return false
            const aStart = normalizeDate(absence.startDate)
            const aEnd = normalizeDate(absence.endDate)
            if (start > aEnd || end < aStart) return false

            const overlapStart = start > aStart ? start : aStart
            const overlapEnd = end < aEnd ? end : aEnd
            const overlapStartDate = parseYmd(overlapStart)
            const overlapEndDate = parseYmd(overlapEnd)
            if (!overlapStartDate || !overlapEndDate) return false

            for (
                let currentDate = new Date(overlapStartDate.getTime());
                currentDate <= overlapEndDate;
                currentDate.setDate(currentDate.getDate() + 1)
            ) {
                const dateKey = toYmd(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate())
                const existingSegments = getSegmentsForDate(
                    aStart,
                    aEnd,
                    absence.startHalf ?? 'AM',
                    absence.endHalf ?? 'PM',
                    dateKey
                )
                const newSegments = getSegmentsForDate(
                    start,
                    end,
                    form.startHalf,
                    form.endHalf,
                    dateKey
                )
                if (existingSegments.some((segment) => newSegments.includes(segment))) {
                    return true
                }
            }

            return false
        })

        if (overlaps.length > 0) {
            // Securise le chevauchement: on demande confirmation avant suppression.
            const confirmReplace = window.confirm(
                "Cette absence chevauche une autre. Voulez-vous la remplacer ?"
            )
            if (!confirmReplace) return
            for (const overlap of overlaps) {
                await deleteAbsence(overlap.id)
            }
        }

        await createAbsence({
            employeeId: Number(form.employeeId),
            typeId: Number(form.typeId),
            startDate: form.startDate,
            startHalf: form.startHalf,
            endDate: form.endDate,
            endHalf: form.endHalf,
            comment: form.comment
        })

        closeDrawer()
        await loadAbsences()
    } finally {
        isSubmitting.value = false
    }
}

// Suppression: efface toutes les absences de l'employé comprises dans la plage
// sélectionnée (date début → date fin du drawer). Comme une absence = une ligne
// par jour en BDD, on supprime chaque jour existant de la plage ; les jours sans
// absence (ex. une date hors plage réelle) sont naturellement ignorés.
const handleDelete = async () => {
    if (!editingAbsence.value) return

    const employeeId = editingAbsence.value.employee.id
    const rangeStart = normalizeDate(form.startDate)
    const rangeEnd = normalizeDate(form.endDate)
    if (rangeStart > rangeEnd) {
        window.alert("La date de fin ne peut pas etre avant la date de debut.")
        return
    }

    const toDelete = absences.value.filter((absence) => {
        if (absence.employee?.id !== employeeId) return false
        const day = normalizeDate(absence.startDate)
        return day >= rangeStart && day <= rangeEnd
    })

    if (toDelete.length === 0) {
        closeDrawer()
        return
    }

    const confirmDelete = window.confirm(
        toDelete.length === 1
            ? 'Supprimer cette absence ?'
            : `Supprimer ${toDelete.length} jours de congé du ${formatYmdToFr(rangeStart)} au ${formatYmdToFr(rangeEnd)} ?`
    )
    if (!confirmDelete) return

    for (const absence of toDelete) {
        await deleteAbsence(absence.id)
    }
    closeDrawer()
    await loadAbsences()
}

// Affiche "Prénom N.".
const formatEmployeeName = (employee: Employee) => {
    const initial = employee.lastName ? `${employee.lastName[0].toUpperCase()}.` : ''
    return `${employee.firstName} ${initial}`.trim()
}

// Impression PDF de l'intervalle sélectionné.
const {printPdf} = usePdfPrinter()
const handlePrint = async () => {
    const params = new URLSearchParams()
    params.set('from', printForm.from)
    params.set('to', printForm.to)
    if (printForm.siteIds.length > 0) {
        params.set('sites', printForm.siteIds.join(','))
    }
    if (printForm.contractNatures.length > 0) {
        params.set('contractNatures', printForm.contractNatures.join(','))
    }
    if (printForm.workContractIds.length > 0) {
        params.set('workContracts', printForm.workContractIds.join(','))
    }
    await printPdf(`/absences/print?${params.toString()}`)
    isPrintOpen.value = false
}

const handleReorder = async (payload: { dragId: number; dropId: number }) => {
    const dragEmployee = employees.value.find((employee) => employee.id === payload.dragId)
    const dropEmployee = employees.value.find((employee) => employee.id === payload.dropId)
    if (!dragEmployee || !dropEmployee) return
    const dragSiteId = dragEmployee.site?.id
    const dropSiteId = dropEmployee.site?.id
    if (!dragSiteId || !dropSiteId || dragSiteId !== dropSiteId) return

    const siteEmployees = [...employees.value]
        .filter((employee) => employee.site?.id === dragSiteId)
        .sort(compareEmployeesInSite)

    const fromIndex = siteEmployees.findIndex((employee) => employee.id === dragEmployee.id)
    const toIndex = siteEmployees.findIndex((employee) => employee.id === dropEmployee.id)
    if (fromIndex < 0 || toIndex < 0 || fromIndex === toIndex) return

    const [moved] = siteEmployees.splice(fromIndex, 1)
    siteEmployees.splice(toIndex, 0, moved)

    const updates: Array<{ id: number; displayOrder: number }> = []
    siteEmployees.forEach((employee, index) => {
        const nextOrder = index + 1
        if ((employee.displayOrder ?? 0) !== nextOrder) {
            updates.push({id: employee.id, displayOrder: nextOrder})
        }
        employee.displayOrder = nextOrder
    })

    if (updates.length === 0) return
    await Promise.all(updates.map((update) => updateEmployeeOrder(update.id, update.displayOrder)))
}
</script>
