"use client"

import { useEffect, useRef, useState, type KeyboardEvent, type ReactNode } from "react"
import { addHours } from "date-fns"
import {
  FocusableStepValue,
  handleStepAdjustKeyDown,
  StepAdjustGroup,
  StepAdjustTimeDecreaseButton,
  StepAdjustTimeIncreaseButton,
} from "@/components/agenda/agenda-step-adjust"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Switch } from "@/components/ui/switch"
import { formatAgendaStepDurationMinutes } from "@/lib/agenda/agenda-date"
import type { AgendaDurationStep } from "@/lib/agenda/agenda-settings-types"
import { cn } from "@/lib/utils"

function toDateInput(d: Date): string {
  const y = d.getFullYear()
  const m = String(d.getMonth() + 1).padStart(2, "0")
  const day = String(d.getDate()).padStart(2, "0")
  return `${y}-${m}-${day}`
}

function toTimeInput(d: Date): string {
  return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`
}

function fromDateAndTime(date: string, time: string): Date | null {
  const [y, mo, d] = date.split("-").map(Number)
  const [h, mi] = time.split(":").map(Number)
  if (![y, mo, d, h, mi].every(Number.isFinite)) return null
  const parsed = new Date(y, mo - 1, d, h, mi, 0, 0)
  return Number.isNaN(parsed.getTime()) ? null : parsed
}

function tabAt(base: number | undefined, offset: number): number | undefined {
  return base !== undefined ? base + offset : undefined
}

const AGENDA_STEP_GROUP_CLASS =
  "w-fit gap-0 border-border/70 bg-mail-surface px-0.5 py-0.5"
const AGENDA_STEP_BUTTON_CLASS = "size-6 shrink-0 [&_svg]:size-3.5"
const AGENDA_STEP_VALUE_SLOT_CLASS =
  "flex h-8 w-[3.875rem] min-w-[3.875rem] max-w-[3.875rem] shrink-0 items-center justify-center"
const AGENDA_STEP_VALUE_CLASS =
  "w-full min-w-0 px-0 text-center text-sm leading-none tabular-nums"
const AGENDA_TIME_INPUT_CLASS = cn(
  AGENDA_STEP_VALUE_CLASS,
  "h-full border-0 bg-transparent font-medium shadow-none focus-visible:ring-0",
  "[&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none",
  "[&::-webkit-datetime-edit]:m-0 [&::-webkit-datetime-edit]:p-0 [&::-webkit-datetime-edit]:text-center",
  "[&::-webkit-datetime-edit-fields-wrapper]:flex [&::-webkit-datetime-edit-fields-wrapper]:w-full [&::-webkit-datetime-edit-fields-wrapper]:items-center [&::-webkit-datetime-edit-fields-wrapper]:justify-center",
  "[&::-webkit-datetime-edit-hour-field]:p-0 [&::-webkit-datetime-edit-minute-field]:p-0 [&::-webkit-datetime-edit-text]:p-0",
)
const AGENDA_DURATION_VALUE_CLASS = "text-center text-sm font-medium leading-none tabular-nums"

function ScheduleLabeledRow({
  label,
  children,
}: {
  label: string
  children: ReactNode
}) {
  return (
    <div className="flex items-center gap-2">
      <span className="w-8 shrink-0 text-center text-[10px] font-medium uppercase tracking-wide text-muted-foreground">
        {label}
      </span>
      <div className="flex min-w-0 flex-1 flex-wrap items-center gap-2">{children}</div>
    </div>
  )
}

function AgendaStepTimeInput({
  value,
  tabIndex,
  onChange,
  onKeyDown,
}: {
  value: string
  tabIndex?: number
  onChange: (value: string) => void
  onKeyDown: (e: KeyboardEvent<HTMLInputElement>) => void
}) {
  return (
    <div className={AGENDA_STEP_VALUE_SLOT_CLASS}>
      <Input
        type="time"
        value={value}
        tabIndex={tabIndex}
        onChange={(e) => onChange(e.target.value)}
        onKeyDown={onKeyDown}
        className={AGENDA_TIME_INPUT_CLASS}
      />
    </div>
  )
}

/** Nombre de tab stops internes (base inclusif → dernier = base + count - 1). */
export function agendaScheduleFieldCount(options: {
  allDay: boolean
  showAllDayToggle: boolean
  compact: boolean
}): number {
  if (options.compact) {
    if (options.allDay) return 1
    return 3
  }
  if (options.allDay) {
    return options.showAllDayToggle ? 3 : 2
  }
  return options.showAllDayToggle ? 6 : 5
}

export function AgendaEventScheduleFields({
  start,
  end,
  allDay,
  stepMinutes,
  onChange,
  showAllDayToggle = false,
  onAllDayChange,
  compact = false,
  showRowLabels = false,
  className,
  tabIndexBase,
}: {
  start: Date
  end: Date
  allDay: boolean
  stepMinutes: AgendaDurationStep
  onChange: (start: Date, end: Date) => void
  showAllDayToggle?: boolean
  onAllDayChange?: (allDay: boolean) => void
  compact?: boolean
  /** Modale avancée : libellés Début / Fin à gauche des deux lignes. */
  showRowLabels?: boolean
  className?: string
  tabIndexBase?: number
}) {
  const startDate = toDateInput(start)
  const endDate = toDateInput(end)
  const startTime = toTimeInput(start)
  const endTime = toTimeInput(end)
  const [endDateOpen, setEndDateOpen] = useState(false)
  const endDateInputRef = useRef<HTMLInputElement>(null)

  useEffect(() => {
    setEndDateOpen(false)
  }, [startDate, endDate, allDay, compact])

  useEffect(() => {
    if (!endDateOpen) return
    const timer = window.setTimeout(() => endDateInputRef.current?.focus(), 0)
    return () => window.clearTimeout(timer)
  }, [endDateOpen])

  const durationMinutes = Math.max(
    stepMinutes,
    Math.round((end.getTime() - start.getTime()) / 60_000),
  )

  const showEndDateField = startDate !== endDate || endDateOpen

  const apply = (nextStart: Date, nextEnd: Date) => {
    if (nextEnd.getTime() <= nextStart.getTime()) {
      onChange(nextStart, addHours(nextStart, 1))
      return
    }
    onChange(nextStart, nextEnd)
  }

  const patchStartDate = (date: string) => {
    const nextStart = fromDateAndTime(date, allDay ? "00:00" : startTime) ?? start
    let nextEnd = end
    if (date > endDate) nextEnd = fromDateAndTime(date, allDay ? "00:00" : endTime) ?? nextStart
    apply(nextStart, nextEnd)
  }

  const patchEndDate = (date: string) => {
    const nextEnd = fromDateAndTime(date, allDay ? "00:00" : endTime) ?? end
    apply(start, nextEnd)
  }

  const patchStartTime = (time: string) => {
    const nextStart = fromDateAndTime(startDate, time)
    if (!nextStart) return
    apply(nextStart, end.getTime() <= nextStart.getTime() ? addHours(nextStart, 1) : end)
  }

  const patchEndTime = (time: string) => {
    const nextEnd = fromDateAndTime(endDate, time)
    if (!nextEnd) return
    apply(start, nextEnd.getTime() <= start.getTime() ? addHours(start, 1) : nextEnd)
  }

  const shiftStart = (deltaMinutes: number) => {
    const nextStart = new Date(start.getTime() + deltaMinutes * 60_000)
    const durationMs = end.getTime() - start.getTime()
    apply(nextStart, new Date(nextStart.getTime() + durationMs))
  }

  const shiftEnd = (deltaMinutes: number) => {
    const nextEnd = new Date(end.getTime() + deltaMinutes * 60_000)
    if (nextEnd.getTime() <= start.getTime()) return
    apply(start, nextEnd)
  }

  const shiftDuration = (deltaMinutes: number) => {
    const nextDuration = Math.max(stepMinutes, durationMinutes + deltaMinutes)
    apply(start, new Date(start.getTime() + nextDuration * 60_000))
  }

  const startDateInput = (
    <Input
      type="date"
      value={startDate}
      tabIndex={tabAt(tabIndexBase, 0)}
      onChange={(e) => patchStartDate(e.target.value)}
      className="h-9 w-fit"
    />
  )

  const startTimeControl = (
    <StepAdjustGroup className={AGENDA_STEP_GROUP_CLASS}>
      <StepAdjustTimeDecreaseButton
        onClick={() => shiftStart(-stepMinutes)}
        label={`Reculer le début de ${stepMinutes} minutes`}
        className={AGENDA_STEP_BUTTON_CLASS}
      />
      <AgendaStepTimeInput
        value={startTime}
        tabIndex={tabAt(tabIndexBase, 1)}
        onChange={patchStartTime}
        onKeyDown={(e) =>
          handleStepAdjustKeyDown(
            e,
            () => shiftStart(-stepMinutes),
            () => shiftStart(stepMinutes),
          )
        }
      />
      <StepAdjustTimeIncreaseButton
        onClick={() => shiftStart(stepMinutes)}
        label={`Avancer le début de ${stepMinutes} minutes`}
        className={AGENDA_STEP_BUTTON_CLASS}
      />
    </StepAdjustGroup>
  )

  const endTimeControl = (
    <StepAdjustGroup className={AGENDA_STEP_GROUP_CLASS}>
      <StepAdjustTimeDecreaseButton
        onClick={() => shiftEnd(-stepMinutes)}
        label={`Reculer la fin de ${stepMinutes} minutes`}
        className={AGENDA_STEP_BUTTON_CLASS}
      />
      <AgendaStepTimeInput
        value={endTime}
        tabIndex={tabAt(tabIndexBase, 3)}
        onChange={patchEndTime}
        onKeyDown={(e) =>
          handleStepAdjustKeyDown(
            e,
            () => shiftEnd(-stepMinutes),
            () => shiftEnd(stepMinutes),
          )
        }
      />
      <StepAdjustTimeIncreaseButton
        onClick={() => shiftEnd(stepMinutes)}
        label={`Avancer la fin de ${stepMinutes} minutes`}
        className={AGENDA_STEP_BUTTON_CLASS}
      />
    </StepAdjustGroup>
  )

  const durationControl = (
    <FocusableStepValue
      tabIndex={tabAt(tabIndexBase, 2)}
      value={formatAgendaStepDurationMinutes(durationMinutes)}
      ariaLabel="Durée"
      onDecrease={() => shiftDuration(-stepMinutes)}
      onIncrease={() => shiftDuration(stepMinutes)}
      decreaseDisabled={durationMinutes <= stepMinutes}
      increaseDisabled={false}
      decreaseLabel={`Réduire la durée de ${stepMinutes} minutes`}
      increaseLabel={`Augmenter la durée de ${stepMinutes} minutes`}
      className={AGENDA_STEP_GROUP_CLASS}
      buttonClassName={AGENDA_STEP_BUTTON_CLASS}
      valueWrapperClassName={AGENDA_STEP_VALUE_SLOT_CLASS}
      valueClassName={AGENDA_DURATION_VALUE_CLASS}
    />
  )

  const endTimeLabel = (
    <span
      className="flex h-8 items-center text-xs tabular-nums text-foreground/80"
      aria-label={`Fin à ${endTime}`}
    >
      {endTime}
    </span>
  )

  const endDateControl = showEndDateField ? (
    <Input
      ref={endDateInputRef}
      type="date"
      value={endDate}
      min={startDate}
      tabIndex={tabAt(tabIndexBase, allDay ? 1 : 4)}
      onChange={(e) => patchEndDate(e.target.value)}
      className="h-9 w-fit"
    />
  ) : (
    <Button
      type="button"
      variant="outline"
      tabIndex={tabAt(tabIndexBase, allDay ? 1 : 4)}
      className="h-9 rounded-full px-3 text-sm font-normal"
      onClick={() => setEndDateOpen(true)}
    >
      Ajouter une date de fin
    </Button>
  )

  const allDayToggle =
    showAllDayToggle && onAllDayChange ? (
      <label className="flex w-fit cursor-pointer items-center gap-2 text-sm text-foreground/80">
        <Switch
          checked={allDay}
          tabIndex={tabAt(tabIndexBase, allDay ? 2 : 5)}
          onCheckedChange={onAllDayChange}
        />
        Toute la journée
      </label>
    ) : null

  if (compact && allDay) {
    return (
      <div className={cn("flex flex-col items-start gap-2", className)}>
        <div className="flex flex-wrap items-center gap-2">
          {startDateInput}
          {startDate !== endDate ? endDateControl : null}
        </div>
        <span className="text-sm text-muted-foreground">Toute la journée</span>
      </div>
    )
  }

  if (compact) {
    return (
      <div className={cn("flex flex-col items-start gap-2", className)}>
        <div className="flex flex-wrap items-center gap-2">
          {startDateInput}
          {startTimeControl}
        </div>
        <div className="flex flex-wrap items-center gap-2">
          {durationControl}
          {endTimeLabel}
        </div>
      </div>
    )
  }

  const scheduleRow = (label: string | null, children: ReactNode) =>
    showRowLabels && label ? (
      <ScheduleLabeledRow label={label}>{children}</ScheduleLabeledRow>
    ) : (
      <div className="flex flex-wrap items-center gap-2">{children}</div>
    )

  if (allDay) {
    return (
      <div className={cn("flex flex-col gap-2", className)}>
        {scheduleRow("Début", startDateInput)}
        {scheduleRow("Fin", endDateControl)}
        {allDayToggle}
      </div>
    )
  }

  return (
    <div className={cn("flex flex-col gap-2", className)}>
      {scheduleRow("Début", (
        <>
          {startDateInput}
          {startTimeControl}
        </>
      ))}
      {scheduleRow("Fin", (
        <>
          {endDateControl}
          {endTimeControl}
          {durationControl}
        </>
      ))}
      {allDayToggle}
    </div>
  )
}
