import type { Ref } from 'vue'
import type { Contract } from '~/services/dto/contract'
import type { ContractHistoryItem, Employee } from '~/services/dto/employee'
import { listContracts } from '~/services/contracts'
import { updateEmployee } from '~/services/employees'
import { createSuspension, updateSuspension } from '~/services/contractSuspensions'
import { listInterimAgencies, type InterimAgency } from '~/services/interim-agencies'
import { formatNullableYmdToFr, getTodayYmd, shiftYmd } from '~/utils/date'
import { contractNatureLabel, formatWorkDaysHoursSummary, isContractNature, requiresContractEndDate, requiresWorkDaysHours, showsContractEndDate } from '~/utils/contract'

type SuspensionForm = {
  id: number | null
  startDate: string
  endDate: string
  comment: string
}

export const useEmployeeContract = (employee: Ref<Employee | null>, reloadEmployee: () => Promise<void>) => {
  const toast = useToast()
  const contracts = ref<Contract[]>([])
  const interimAgencies = ref<InterimAgency[]>([])
  const isContractDrawerOpen = ref(false)
  const isContractSubmitting = ref(false)
  const isCreateContractDrawerOpen = ref(false)
  const isCreateContractSubmitting = ref(false)
  const suspensionForms = ref<SuspensionForm[]>([])
  const isSuspensionSubmitting = ref(false)

  const contractForm = reactive({
    contractId: '' as number | '',
    contractName: '',
    weeklyHours: null as number | null,
    contractNature: 'CDI' as 'CDI' | 'CDD' | 'INTERIM',
    startDate: '',
    endDate: '',
    paidLeaveSettled: false,
    comment: '',
    workDaysHours: null as Record<number, number> | null
  })

  const validationTouched = reactive({
    endDate: false
  })

  const createContractForm = reactive({
    contractId: '' as number | '',
    contractNature: 'CDI' as 'CDI' | 'CDD' | 'INTERIM',
    startDate: '',
    endDate: '',
    isDriver: false,
    workDaysHours: null as Record<number, number> | null,
    interimAgencyId: '' as number | ''
  })

  const createValidationTouched = reactive({
    contractId: false,
    contractNature: false,
    startDate: false,
    endDate: false
  })

  const contractHistory = computed(() => employee.value?.contractHistory ?? [])

  const formatDate = (value?: string | null) => formatNullableYmdToFr(value)

  const contractHistoryLabel = (item: ContractHistoryItem) => {
    const base = item.weeklyHours !== null && item.weeklyHours !== undefined
      ? `${item.weeklyHours} heures`
      : (item.contractName ?? '-')
    const scheduleSummary = formatWorkDaysHoursSummary(item.workDaysHours)
    return scheduleSummary ? `${base} (${scheduleSummary})` : base
  }

  const currentActiveContractPeriod = computed(() => {
    const today = getTodayYmd()
    const history = employee.value?.contractHistory ?? []
    return history.find((item) => item.startDate <= today && (!item.endDate || item.endDate >= today)) ?? null
  })

  const lastEndedContractPeriod = computed(() => {
    if (currentActiveContractPeriod.value) return null
    const today = getTodayYmd()
    const history = employee.value?.contractHistory ?? []
    const ended = history.filter((item) => item.endDate && item.endDate < today)
    if (ended.length === 0) return null
    return ended.reduce((latest, item) => (item.endDate! > latest.endDate! ? item : latest))
  })

  const editableContractPeriod = computed(() => currentActiveContractPeriod.value ?? lastEndedContractPeriod.value)

  const currentActiveContractPeriodId = computed<number | null>(() => {
    const period = currentActiveContractPeriod.value
    return period?.periodId ?? null
  })

  const canCloseCurrentContract = computed(() => {
    const active = currentActiveContractPeriod.value
    if (active) {
      if (!active.endDate) return true
      return active.endDate > getTodayYmd()
    }
    return !!lastEndedContractPeriod.value
  })

  const canCreateContract = computed(() => {
    const active = editableContractPeriod.value
    if (!active) return true
    return !!active.endDate
  })

  const isContractEndDateValid = computed(() => contractForm.endDate !== '')
  const showContractEndDateError = computed(() => validationTouched.endDate && !isContractEndDateValid.value)

  const showsCreateContractEndDate = computed(() => showsContractEndDate(createContractForm.contractNature))
  const requiresCreateContractEndDate = computed(() => requiresContractEndDate(createContractForm.contractNature))
  const isCreateContractValid = computed(() => createContractForm.contractId !== '')
  const isCreateContractNatureValid = computed(() => isContractNature(createContractForm.contractNature))
  const isCreateContractStartDateValid = computed(() => createContractForm.startDate !== '')
  const isCreateContractEndDateValid = computed(() => !requiresCreateContractEndDate.value || createContractForm.endDate !== '')
  const selectedCreateContract = computed<Contract | null>(() =>
    contracts.value.find((c) => c.id === Number(createContractForm.contractId)) ?? null
  )
  const requiresCreateWorkDaysHours = computed(() =>
    requiresWorkDaysHours(selectedCreateContract.value, createContractForm.contractNature)
  )
  const createScheduleTotalMinutes = computed(() => {
    const raw = createContractForm.workDaysHours ?? {}
    return Object.values(raw).reduce((s, n) => s + (Number(n) || 0), 0)
  })
  const isCreateScheduleValid = computed(() => {
    if (!requiresCreateWorkDaysHours.value) return true
    const expected = (selectedCreateContract.value?.weeklyHours ?? 0) * 60
    return expected > 0 && createScheduleTotalMinutes.value === expected
  })
  const isCreateContractFormValid = computed(() =>
    isCreateContractValid.value &&
    isCreateContractNatureValid.value &&
    isCreateContractStartDateValid.value &&
    isCreateContractEndDateValid.value &&
    isCreateScheduleValid.value
  )

  const baseInputClass =
    'mt-2 w-full rounded-md border px-3 py-2 text-base text-neutral-900 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-secondary-500/20'
  const readonlyFieldClass = `${baseInputClass} border-neutral-300 bg-neutral-100 text-neutral-700`
  const contractEndDateFieldClass = computed(() => showContractEndDateError.value ? `${baseInputClass} border-red-500` : `${baseInputClass} border-neutral-300`)
  const baseSelectClass = 'mt-2 w-full rounded-md border bg-white px-3 py-2 text-md text-neutral-900'
  const createContractFieldClass = computed(() => createValidationTouched.contractId && !isCreateContractValid.value ? `${baseSelectClass} border-red-500` : `${baseSelectClass} border-neutral-300`)
  const createContractNatureFieldClass = computed(() => createValidationTouched.contractNature && !isCreateContractNatureValid.value ? `${baseSelectClass} border-red-500` : `${baseSelectClass} border-neutral-300`)
  const createContractStartDateFieldClass = computed(() => createValidationTouched.startDate && !isCreateContractStartDateValid.value ? `${baseInputClass} border-red-500` : `${baseInputClass} border-neutral-300`)
  const createContractEndDateFieldClass = computed(() => createValidationTouched.endDate && !isCreateContractEndDateValid.value ? `${baseInputClass} border-red-500` : `${baseInputClass} border-neutral-300`)
  const closeContractWorkedHoursLabel = computed(() => {
    if (contractForm.weeklyHours !== null && contractForm.weeklyHours !== undefined) return `${contractForm.weeklyHours} heures`
    return contractForm.contractName || '-'
  })

  const resetContractValidation = () => {
    validationTouched.endDate = false
  }

  const hydrateSuspensionForms = () => {
    const current = employee.value?.currentSuspensions ?? []
    suspensionForms.value = current.map(s => ({
      id: s.id,
      startDate: s.startDate,
      endDate: s.endDate ?? '',
      comment: s.comment ?? ''
    }))
  }

  const hydrateContractFormFromCurrent = () => {
    const current = employee.value
    const period = editableContractPeriod.value
    if (!current || !period) return

    contractForm.contractId = period.contractId ?? current.contract?.id ?? ''
    contractForm.contractName = period.contractName ?? current.contract?.name ?? ''
    contractForm.weeklyHours = period.weeklyHours ?? current.contract?.weeklyHours ?? null
    contractForm.contractNature = period.contractNature
    contractForm.startDate = period.startDate
    contractForm.endDate = period.endDate ?? getTodayYmd()
    contractForm.paidLeaveSettled = false
    contractForm.comment = ''
    contractForm.workDaysHours = period.workDaysHours ?? null
  }

  const openCloseContractDrawer = () => {
    if (!employee.value || !canCloseCurrentContract.value) return
    hydrateContractFormFromCurrent()
    resetContractValidation()
    hydrateSuspensionForms()
    isContractDrawerOpen.value = true
  }

  const setContractDrawerOpen = (open: boolean) => {
    isContractDrawerOpen.value = open
  }

  const resetCreateValidation = () => {
    createValidationTouched.contractId = false
    createValidationTouched.contractNature = false
    createValidationTouched.startDate = false
    createValidationTouched.endDate = false
  }

  const openCreateContractDrawer = () => {
    if (!employee.value || !canCreateContract.value) return
    createContractForm.contractId = ''
    createContractForm.contractNature = 'CDI'
    createContractForm.endDate = ''
    createContractForm.isDriver = false
    createContractForm.workDaysHours = null
    createContractForm.interimAgencyId = ''
    createContractForm.startDate = editableContractPeriod.value?.endDate
      ? (shiftYmd(editableContractPeriod.value.endDate, 1) ?? editableContractPeriod.value.endDate)
      : getTodayYmd()
    resetCreateValidation()
    isCreateContractDrawerOpen.value = true
  }

  const setCreateContractDrawerOpen = (open: boolean) => {
    isCreateContractDrawerOpen.value = open
  }

  const submitContractUpdate = async () => {
    const period = editableContractPeriod.value
    if (!employee.value || isContractSubmitting.value || !period) return

    validationTouched.endDate = true
    if (!isContractEndDateValid.value) return

    if (contractForm.endDate < period.startDate) {
      toast.error({
        title: 'Erreur',
        message: `La date de fin doit être postérieure au ${formatDate(period.startDate)}.`
      })
      return
    }

    isContractSubmitting.value = true
    try {
      await updateEmployee(employee.value.id, {
        firstName: employee.value.firstName,
        lastName: employee.value.lastName,
        siteId: employee.value.site?.id ?? null,
        contractId: Number(contractForm.contractId),
        contractEndDate: contractForm.endDate || null,
        contractPaidLeaveSettled: contractForm.paidLeaveSettled,
        contractComment: contractForm.comment || null
      })

      isContractDrawerOpen.value = false
      await reloadEmployee()
    } finally {
      isContractSubmitting.value = false
    }
  }

  const submitCreateContract = async () => {
    if (!employee.value || isCreateContractSubmitting.value) return

    createValidationTouched.contractId = true
    createValidationTouched.contractNature = true
    createValidationTouched.startDate = true
    createValidationTouched.endDate = true
    if (!isCreateContractFormValid.value) return

    if (editableContractPeriod.value?.endDate) {
      const minStartDate = shiftYmd(editableContractPeriod.value.endDate, 1) ?? editableContractPeriod.value.endDate
      if (createContractForm.startDate < minStartDate) {
        toast.error({
          title: 'Erreur',
          message: `La date de début doit être au moins le ${formatDate(minStartDate)}.`
        })
        return
      }
    }

    isCreateContractSubmitting.value = true
    try {
      await updateEmployee(employee.value.id, {
        firstName: employee.value.firstName,
        lastName: employee.value.lastName,
        siteId: employee.value.site?.id ?? null,
        contractId: Number(createContractForm.contractId),
        contractNature: createContractForm.contractNature,
        contractStartDate: createContractForm.startDate,
        contractEndDate: createContractForm.endDate || null,
        isDriverInput: createContractForm.isDriver,
        workDaysHoursInput: requiresCreateWorkDaysHours.value ? createContractForm.workDaysHours : null,
        interimAgencyId: createContractForm.contractNature === 'INTERIM' && createContractForm.interimAgencyId !== '' ? Number(createContractForm.interimAgencyId) : null
      })
      isCreateContractDrawerOpen.value = false
      await reloadEmployee()
    } finally {
      isCreateContractSubmitting.value = false
    }
  }

  const submitSuspension = async (index: number) => {
    const form = suspensionForms.value[index]
    if (!form || !form.startDate) return

    const periodId = currentActiveContractPeriodId.value
    if (!periodId) return

    isSuspensionSubmitting.value = true
    try {
      if (form.id) {
        await updateSuspension(form.id, {
          startDate: form.startDate,
          endDate: form.endDate || null,
          comment: form.comment || null
        })
      } else {
        await createSuspension({
          contractPeriodId: periodId,
          startDate: form.startDate,
          endDate: form.endDate || null,
          comment: form.comment || null
        })
      }
      await reloadEmployee()
      hydrateSuspensionForms()
    } finally {
      isSuspensionSubmitting.value = false
    }
  }

  const addSuspensionForm = () => {
    suspensionForms.value.push({
      id: null,
      startDate: '',
      endDate: '',
      comment: ''
    })
  }

  const loadContracts = async () => {
    contracts.value = await listContracts()
  }

  const loadInterimAgencies = async () => {
    interimAgencies.value = await listInterimAgencies()
  }

  watch(() => createContractForm.contractNature, (nature) => {
    if (nature !== 'INTERIM') {
      createContractForm.interimAgencyId = ''
    }
  })

  watch(showsCreateContractEndDate, (shows) => {
    if (!shows) {
      createContractForm.endDate = ''
    }
  })

  watch(requiresCreateWorkDaysHours, (required) => {
    if (!required) {
      createContractForm.workDaysHours = null
    }
  })

  return {
    contracts,
    contractHistory,
    contractForm,
    createContractForm,
    isContractDrawerOpen,
    isContractSubmitting,
    isCreateContractDrawerOpen,
    isCreateContractSubmitting,
    canCloseCurrentContract,
    canCreateContract,
    readonlyFieldClass,
    closeContractWorkedHoursLabel,
    contractEndDateFieldClass,
    showContractEndDateError,
    isContractEndDateValid,
    createContractNatureFieldClass,
    createContractFieldClass,
    createContractStartDateFieldClass,
    showsCreateContractEndDate,
    requiresCreateContractEndDate,
    createContractEndDateFieldClass,
    isCreateContractFormValid,
    requiresCreateWorkDaysHours,
    selectedCreateContract,
    contractNatureLabel,
    contractHistoryLabel,
    formatDate,
    openCloseContractDrawer,
    openCreateContractDrawer,
    setContractDrawerOpen,
    setCreateContractDrawerOpen,
    submitContractUpdate,
    submitCreateContract,
    suspensionForms,
    isSuspensionSubmitting,
    submitSuspension,
    addSuspensionForm,
    currentActiveContractPeriodId,
    interimAgencies,
    loadContracts,
    loadInterimAgencies
  }
}
