import type { Ref } from 'vue'
import type { Absence } from '~/services/dto/absence'
import type { ContractPhase } from '~/services/dto/contract-phase'
import type { EmployeeLeaveSummary } from '~/services/dto/employee-leave-summary'
import type { Employee } from '~/services/dto/employee'
import { CONTRACT_TYPES } from '~/services/dto/contract'
import { listAbsences } from '~/services/absences'
import { getEmployeeLeaveSummary, updateFractionedDays, updatePaidLeaveDays } from '~/services/employee-leave-summary'
import { listPublicHolidays } from '~/services/public-holidays'

export type LeaveYearOption = {
  value: number
  label: string
}

export const useEmployeeLeave = (
  employee: Ref<Employee | null>,
  reloadEmployee: () => Promise<void>,
  selectedPhase: Ref<ContractPhase | null>,
) => {
  const employeeAbsences = ref<Absence[]>([])
  const leaveSummary = ref<EmployeeLeaveSummary | null>(null)
  const publicHolidays = ref<Record<string, string>>({})
  const isLeaveLoading = ref(false)
  const leaveDataLoaded = ref(false)
  const selectedLeaveYear = ref<number | null>(null)

  const isForfaitOnPhase = computed(() =>
    selectedPhase.value?.contractType === CONTRACT_TYPES.FORFAIT
  )

  const computeLeaveYearForDate = (date: Date): number => {
    if (isForfaitOnPhase.value) return date.getFullYear()
    return date.getMonth() >= 5 ? date.getFullYear() + 1 : date.getFullYear()
  }

  const currentLeaveYear = computed<number | null>(() => {
    if (!employee.value) return null
    return computeLeaveYearForDate(new Date())
  })

  const formatLeaveYearLabel = (year: number, isForfait: boolean): string => {
    if (isForfait) return String(year)
    return `Juin ${year - 1} → Mai ${year}`
  }

  const availableLeaveYears = computed<LeaveYearOption[]>(() => {
    if (!employee.value || !selectedPhase.value || currentLeaveYear.value === null) return []
    const isForfait = isForfaitOnPhase.value
    const phase = selectedPhase.value

    // Plage = exercices intersectant la phase.
    const phaseStartYear = computeLeaveYearForDate(new Date(`${phase.startDate}T00:00:00`))
    // Borne haute : fin de phase si clôturée ; sinon l'exercice SUIVANT (courant + 1),
    // pour pouvoir consulter en avance les congés posés sur l'exercice à venir.
    const maxYear = phase.endDate
      ? computeLeaveYearForDate(new Date(`${phase.endDate}T00:00:00`))
      : currentLeaveYear.value + 1

    // Hard floor : data-start-date (env RTT_START_DATE) — le logiciel n'a pas
    // d'historique avant cette date, inutile de proposer des années antérieures.
    let dataFloor: number | null = null
    const dataStart = leaveSummary.value?.dataStartDate
    if (dataStart) {
      const dataStartDate = new Date(`${dataStart.substring(0, 10)}T00:00:00`)
      if (!Number.isNaN(dataStartDate.getTime())) {
        dataFloor = computeLeaveYearForDate(dataStartDate)
      }
    }

    const minYear = dataFloor !== null ? Math.max(phaseStartYear, dataFloor) : phaseStartYear

    const years: LeaveYearOption[] = []
    for (let y = maxYear; y >= minYear; y -= 1) {
      years.push({ value: y, label: formatLeaveYearLabel(y, isForfait) })
    }
    return years
  })

  const initSelectedLeaveYear = () => {
    if (selectedLeaveYear.value !== null) return
    if (currentLeaveYear.value !== null) {
      selectedLeaveYear.value = currentLeaveYear.value
    }
  }

  const loadLeaveData = async () => {
    if (!employee.value || isLeaveLoading.value) return
    initSelectedLeaveYear()
    if (selectedLeaveYear.value === null) return
    isLeaveLoading.value = true
    try {
      const isForfait = isForfaitOnPhase.value
      const leaveYear = selectedLeaveYear.value
      let from = isForfait ? `${leaveYear}-01-01` : `${leaveYear - 1}-06-01`
      let to = isForfait ? `${leaveYear}-12-31` : `${leaveYear}-05-31`
      const phase = selectedPhase.value
      if (phase?.startDate && phase.startDate > from) from = phase.startDate
      if (phase?.endDate && phase.endDate < to) to = phase.endDate
      const holidayYears = isForfait ? [leaveYear] : [leaveYear - 1, leaveYear]

      const [absences, summary, ...holidayResults] = await Promise.all([
        listAbsences({ from, to, employeeId: employee.value.id }),
        getEmployeeLeaveSummary(employee.value.id, leaveYear, selectedPhase.value?.id),
        ...holidayYears.map((y) => listPublicHolidays('metropole', y))
      ])
      employeeAbsences.value = absences
      leaveSummary.value = summary
      publicHolidays.value = Object.assign({}, ...holidayResults)
      leaveDataLoaded.value = true
    } finally {
      isLeaveLoading.value = false
    }
  }

  const setSelectedLeaveYear = async (year: number) => {
    if (selectedLeaveYear.value === year) return
    selectedLeaveYear.value = year
    leaveDataLoaded.value = false
    await loadLeaveData()
  }

  const resetLoaded = () => {
    leaveDataLoaded.value = false
    selectedLeaveYear.value = null
  }

  watch(() => selectedPhase.value?.id, (newId, oldId) => {
    // Ignore la résolution initiale (undefined → phase courante au montage) :
    // le chargement eager du récap initialise déjà l'année sélectionnée. Sans ce
    // garde, ce watch (asynchrone) s'exécute PENDANT l'await du chargement eager et
    // remet selectedLeaveYear à null, ce qui laisse le sélecteur d'exercice vide.
    // Même convention que le watch de useEmployeeDetailPage.
    if (oldId === undefined || newId === oldId) return
    // Changement de phase réel : reset l'année car la plage a peut-être changé.
    selectedLeaveYear.value = null
    leaveDataLoaded.value = false
    // Le rechargement effectif est piloté par useEmployeeDetailPage.
  })

  const submitFractionedDays = async (days: number) => {
    if (!employee.value) return
    const year = leaveSummary.value?.year ?? undefined
    await updateFractionedDays(employee.value.id, days, year)
    await reloadEmployee()
  }

  const submitPaidLeaveDays = async (days: number) => {
    if (!employee.value) return
    const year = leaveSummary.value?.year ?? undefined
    await updatePaidLeaveDays(employee.value.id, days, year)
    await reloadEmployee()
  }

  return {
    employeeAbsences,
    leaveSummary,
    publicHolidays,
    isLeaveLoading,
    leaveDataLoaded,
    selectedLeaveYear,
    currentLeaveYear,
    availableLeaveYears,
    setSelectedLeaveYear,
    loadLeaveData,
    resetLoaded,
    submitFractionedDays,
    submitPaidLeaveDays
  }
}
