import { format } from "date-fns"
import { enUS, zhCN } from "date-fns/locale"
import { CalendarIcon } from "lucide-react"
import { useRef } from "react"
import { useTranslation } from "react-i18next"
import { enUS as enUSDayPicker, zhCN as zhCNDayPicker } from "react-day-picker/locale"

import { Button } from "@/components/ui/button"
import { Calendar } from "@/components/ui/calendar"
import { Input } from "@/components/ui/input"
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
import { cn } from "@/shared/lib/cn"
import { toDateTimeLocal } from "@/shared/lib/format"

type DateTimePickerProps = {
  value: string
  onChange: (value: string) => void
  placeholder?: string
  disabled?: boolean
}

export function DateTimePicker({ value, onChange, placeholder, disabled = false }: DateTimePickerProps) {
  const { t, i18n } = useTranslation()
  const selected = parseLocalDateTime(value)
  const isChinese = i18n.language.toLowerCase().startsWith("zh")
  const timeParts = getTimeParts(selected)
  const timeInputRefs = useRef<Array<HTMLInputElement | null>>([])

  function enteredTimeParts(): TimeParts {
    return timeParts.map((part, index) => timeInputRefs.current[index]?.value ?? part) as TimeParts
  }

  function selectDate(date: Date | undefined): void {
    if (!date) {
      onChange("")
      return
    }
    const [hours, minutes, seconds] = normalizedTimeParts(enteredTimeParts())
    date.setHours(hours, minutes, seconds, 0)
    onChange(toDateTimeLocal(date.toISOString()))
  }

  function commitTime(): void {
    const normalized = normalizedTimeParts(enteredTimeParts())
    const date = selected ? new Date(selected) : new Date()
    date.setHours(normalized[0], normalized[1], normalized[2], 0)
    onChange(toDateTimeLocal(date.toISOString()))
  }

  return (
    <Popover>
      <PopoverTrigger asChild>
        <Button type="button" variant="secondary" disabled={disabled} className={cn("h-8 w-full min-w-0 justify-start rounded-md bg-secondary/55 px-3 text-left font-normal", !selected && "text-muted-foreground")}>
          <CalendarIcon />
          <span className="truncate">
            {selected ? format(selected, isChinese ? "yyyy年M月d日 HH:mm:ss" : "MMM d, yyyy HH:mm:ss", { locale: isChinese ? zhCN : enUS }) : (placeholder ?? t("keys.neverExpires"))}
          </span>
        </Button>
      </PopoverTrigger>
      <PopoverContent className="w-auto overflow-hidden p-0" align="start">
        <Calendar
          mode="single"
          selected={selected}
          defaultMonth={selected}
          onSelect={selectDate}
          locale={isChinese ? zhCNDayPicker : enUSDayPicker}
        />
        <div className="flex items-center gap-2 border-t px-3 py-2">
          <span className="text-xs text-muted-foreground">{t("keys.expiryTime")}</span>
          <div className="ml-auto flex items-center gap-1 text-xs">
            {timeParts.map((part, index) => (
              <div className="contents" key={index}>
                {index > 0 ? <span className="text-muted-foreground">:</span> : null}
                <Input
                  aria-label={`${t("keys.expiryTime")} ${index === 0 ? "HH" : index === 1 ? "MM" : "SS"}`}
                  className="h-7 w-9 bg-background px-1 text-center text-xs tabular-nums"
                  inputMode="numeric"
                  maxLength={2}
                  pattern="[0-9]*"
                  defaultValue={part}
                  key={`${value}-${index}`}
                  ref={(element) => {
                    timeInputRefs.current[index] = element
                  }}
                  onChange={(event) => {
                    event.currentTarget.value = event.currentTarget.value.replace(/\D/g, "").slice(0, 2)
                  }}
                  onBlur={commitTime}
                  onFocus={(event) => event.currentTarget.select()}
                  onKeyDown={(event) => {
                    if (event.key === "Enter") {
                      commitTime()
                      event.currentTarget.blur()
                    }
                  }}
                />
              </div>
            ))}
          </div>
        </div>
      </PopoverContent>
    </Popover>
  )
}

type TimeParts = [string, string, string]

function getTimeParts(date: Date | undefined): TimeParts {
  return date ? [format(date, "HH"), format(date, "mm"), format(date, "ss")] : ["23", "59", "59"]
}

function normalizedTimeParts(parts: TimeParts): [number, number, number] {
  return [
    clampTimePart(parts[0], 23),
    clampTimePart(parts[1], 59),
    clampTimePart(parts[2], 59),
  ]
}

function clampTimePart(value: string, maximum: number): number {
  const parsed = Number.parseInt(value, 10)
  return Number.isNaN(parsed) ? 0 : Math.min(Math.max(parsed, 0), maximum)
}

function parseLocalDateTime(value: string): Date | undefined {
  if (!value) {
    return undefined
  }
  const date = new Date(value)
  return Number.isNaN(date.getTime()) ? undefined : date
}
