<template>
    <section class="flex h-full min-h-0 flex-col overflow-hidden pt-8">
        <div class="grid grid-cols-4 rounded-md bg-primary-500 text-white text-[20]">
            <div class="flex flex-col gap-2 jutify-center items-center border-r-4 border-white py-3">
                <p><strong class="uppercase font-semibold">Année acquis :</strong> {{
                        formatCount(summary?.acquiredDays)
                    }} Jours</p>
                <p><strong class="uppercase font-semibold">Reste à prendre :</strong>
                    {{ formatCount(summary?.remainingDays) }} Jours</p>
            </div>
            <div class="flex flex-col gap-2 jutify-center items-center border-r-4 border-white py-3">
                <p><span class="uppercase font-semibold">Samedi acquis :</span>
                    {{ formatCount(summary?.acquiredSaturdays) }} Jours</p>
                <p><span class="uppercase font-semibold">Reste à prendre :</span>
                    {{ formatCount(summary?.remainingSaturdays) }} Jours</p>
            </div>
            <div class="flex flex-col gap-2 jutify-center items-center border-r-4 border-white py-3">
                <p><span class="uppercase font-semibold">Fractionné acquis : </span>{{ formatCount(summary?.fractionedDays) }} Jours</p>
                <button
                    class="flex justify-center items-center gap-2 bg-white text-primary-500 font-bold w-[150px] rounded-md py-[1px]"
                    @click="openFractionedDrawer"
                >
                    {{ summary?.fractionedDays === 0 ? '+ Ajouter' : 'Modifier' }}</button>
            </div>
            <div class="flex flex-col jutify-center gap-2 items-center py-3">
                <p><span class="uppercase font-semibold">En cours d'acquisition :</span></p>
                <p>{{ formatCount(summary?.accruingDays) }} Jours</p>
            </div>
        </div>
        <div class="mt-8 min-h-0 flex-1 overflow-y-auto pr-2">
            <div class="grid grid-cols-4 gap-10">
                <div v-for="month in months" :key="month.label" class="rounded-md bg-tertiary-500 text-primary-500 flex flex-col justify-between">
                    <div class="flex justify-center rounded-t-md bg-primary-500 py-1 font-bold uppercase text-white">
                        {{ month.label }}
                    </div>
                    <div class="grid grid-cols-7 gap-1 px-2 py-2 text-center text-md font-bold">
                        <p v-for="weekday in weekDayLabels" :key="weekday">{{ weekday }}</p>
                    </div>
                    <div class="grid grid-cols-7 gap-4 px-2 pb-2 text-center text-md">
                        <template v-for="(day, index) in month.cells" :key="`${month.label}-${index}`">
                            <div v-if="!day" class="h-6"/>
                            <div
                                v-else
                                class="flex items-center justify-center"
                            >
                                <div
                                    class="h-6 w-6"
                                    :class="getDayClass(day)"
                                    :style="getDayStyle(day)"
                                    :title="getDayTitle(day)"
                                >
                                    {{ getDayText(day) }}
                                </div>
                            </div>
                        </template>
                    </div>
                    <div class="px-2 py-2 text-center border-t border-primary-500">Jours de présence : {{ summary?.presenceDaysByMonth?.[month.monthKey] ?? 0 }}</div>
                </div>
            </div>
        </div>
        <AppDrawer v-model="isFractionedDrawerOpen" title="Jours fractionnés">
            <form class="space-y-4" @submit.prevent="handleSubmitFractioned">
                <div>
                    <label class="text-md font-semibold text-neutral-700" for="fractioned-days">
                        Nombre de jours <span class="text-red-600">*</span>
                    </label>
                    <input
                        id="fractioned-days"
                        v-model="fractionedForm.days"
                        type="number"
                        step="0.5"
                        min="0"
                        class="mt-2 w-full rounded-md border border-neutral-300 px-3 py-2 text-md text-neutral-900 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-secondary-500/20"
                    />
                </div>

                <div class="flex justify-end gap-3 pt-2">
                    <button
                        type="button"
                        class="rounded-lg border border-neutral-200 px-4 py-2 text-md font-semibold text-neutral-700 hover:bg-neutral-100"
                        @click="isFractionedDrawerOpen = false"
                    >
                        Annuler
                    </button>
                    <button
                        type="submit"
                        class="rounded-lg bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500"
                    >
                        Enregistrer
                    </button>
                </div>
            </form>
        </AppDrawer>
    </section>
</template>

<script setup lang="ts">
import type {Absence} from '~/services/dto/absence'
import type {EmployeeLeaveSummary} from '~/services/dto/employee-leave-summary'
import {normalizeDate, toYmd} from '~/utils/date'
import AppDrawer from '~/components/AppDrawer.vue'

type DayLeaveState = {
    am: boolean
    pm: boolean
    labels: string[]
    colors: string[]
}

const props = defineProps<{
    absences: Absence[]
    summary: EmployeeLeaveSummary | null
    publicHolidays: Record<string, string>
}>()

const emit = defineEmits<{
    (event: 'update-fractioned-days', days: number): void
}>()

const isFractionedDrawerOpen = ref(false)
const fractionedForm = reactive({ days: 0 })

const openFractionedDrawer = () => {
    fractionedForm.days = props.summary?.fractionedDays ?? 0
    isFractionedDrawerOpen.value = true
}

const handleSubmitFractioned = () => {
    const value = Number(fractionedForm.days)
    if (Number.isNaN(value) || value < 0) return
    emit('update-fractioned-days', value)
    isFractionedDrawerOpen.value = false
}

const monthLabels = [
    'Janvier',
    'Fevrier',
    'Mars',
    'Avril',
    'Mai',
    'Juin',
    'Juillet',
    'Aout',
    'Septembre',
    'Octobre',
    'Novembre',
    'Decembre'
] as const

const weekDayLabels = ['L', 'M', 'M', 'J', 'V', 'S', 'D'] as const

const isForfaitRule = computed(() => props.summary?.ruleCode === 'FORFAIT_218')

const displayedYear = computed(() => {
    if (props.summary?.year) return props.summary.year
    const today = new Date()
    const year = today.getFullYear()
    const month = today.getMonth() + 1
    return month >= 6 ? year + 1 : year
})

const orderedMonthIndexes = computed(() => {
    if (isForfaitRule.value) return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
    return [5, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4]
})

const buildDateFromYmd = (value: string) => new Date(`${value}T00:00:00`)

const dayLeaveMap = computed(() => {
    const map = new Map<string, DayLeaveState>()

    for (const absence of props.absences) {
        const startYmd = normalizeDate(absence.startDate)
        const endYmd = normalizeDate(absence.endDate)
        const start = buildDateFromYmd(startYmd)
        const end = buildDateFromYmd(endYmd)
        if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) continue

        for (const cursor = new Date(start); cursor <= end; cursor.setDate(cursor.getDate() + 1)) {
            const ymd = toYmd(cursor.getFullYear(), cursor.getMonth(), cursor.getDate())
            const existing = map.get(ymd) ?? {
                am: false,
                pm: false,
                labels: [] as string[],
                colors: [] as string[]
            }

            const isStart = ymd === startYmd
            const isEnd = ymd === endYmd
            const isSingleDay = startYmd === endYmd

            let am = false
            let pm = false

            if (isSingleDay) {
                am = absence.startHalf === 'AM'
                pm = absence.endHalf === 'PM'
            } else if (isStart) {
                am = absence.startHalf === 'AM'
                pm = true
            } else if (isEnd) {
                am = true
                pm = absence.endHalf === 'PM'
            } else {
                am = true
                pm = true
            }

            const typeLabel = absence.type?.label ?? absence.type?.code ?? 'Absence'
            const typeColor = absence.type?.color ?? '#222783'
            const halfSuffix = am && !pm ? ' (Matin)' : (!am && pm ? ' (Apres-midi)' : '')
            const hoverLabel = `${typeLabel}${halfSuffix}`

            const colors = existing.colors.includes(typeColor)
                ? existing.colors
                : [...existing.colors, typeColor]

            map.set(ymd, {
                am: existing.am || am,
                pm: existing.pm || pm,
                labels: existing.labels.includes(hoverLabel)
                    ? existing.labels
                    : [...existing.labels, hoverLabel],
                colors
            })
        }
    }

    return map
})

const months = computed(() => {
    return orderedMonthIndexes.value.map((monthIndex) => {
        const label = monthLabels[monthIndex]
        const monthYear = isForfaitRule.value
            ? displayedYear.value
            : (monthIndex >= 5 ? displayedYear.value - 1 : displayedYear.value)

        const first = new Date(monthYear, monthIndex, 1)
        const daysInMonth = new Date(monthYear, monthIndex + 1, 0).getDate()
        const mondayBasedFirstDay = (first.getDay() + 6) % 7

        const cells: Array<{ ymd: string; label: string; leave: DayLeaveState | null; isHoliday: boolean } | null> = []

        for (let i = 0; i < mondayBasedFirstDay; i += 1) {
            cells.push(null)
        }

        for (let day = 1; day <= daysInMonth; day += 1) {
            const ymd = toYmd(monthYear, monthIndex, day)
            cells.push({
                ymd,
                label: String(day),
                leave: dayLeaveMap.value.get(ymd) ?? null,
                isHoliday: ymd in props.publicHolidays
            })
        }

        while (cells.length % 7 !== 0) {
            cells.push(null)
        }

        const monthKey = `${monthYear}-${String(monthIndex + 1).padStart(2, '0')}`

        return {
            label,
            cells,
            monthKey
        }
    })
})

const getDayClass = (day: { leave: DayLeaveState | null; isHoliday: boolean }) => {
    if (day.leave) {
        return 'rounded font-semibold text-white'
    }
    if (day.isHoliday) return 'text-primary-500 rounded font-semibold'
    return 'text-primary-500'
}

const getDayStyle = (day: { leave: DayLeaveState | null; isHoliday: boolean }) => {
    if (day.leave) {
        const color = day.leave.colors[0] ?? '#222783'
        if (day.leave.am && day.leave.pm) {
            return { backgroundColor: color }
        }
        const colorFaded = `${color}60`
        const backgroundImage = day.leave.am
            ? `linear-gradient(180deg, ${color} 0 50%, ${colorFaded} 50% 100%)`
            : `linear-gradient(180deg, ${colorFaded} 0 50%, ${color} 50% 100%)`
        return { backgroundImage, backgroundColor: 'transparent' }
    }
    if (day.isHoliday) return { backgroundColor: 'rgb(179, 229, 252)' }
    return undefined
}

const getDayText = (day: { label: string; leave: DayLeaveState | null }) => {
    return day.label
}

const getDayTitle = (day: { leave: DayLeaveState | null; isHoliday: boolean; ymd: string }) => {
    if (day.leave && day.leave.labels.length > 0) return day.leave.labels.join(' / ')
    if (day.isHoliday) return props.publicHolidays[day.ymd] ?? 'Jour férié'
    return ''
}

const formatCount = (value: number | null | undefined) => {
    if (value === null || value === undefined) return '-'
    const rounded = Math.round(value * 100) / 100
    if (Number.isInteger(rounded)) return String(rounded)
    return rounded.toFixed(2).replace('.', ',')
}
</script>
