import * as React from 'react'
import { cn } from './utils'
import { Calendar } from './calendar'

export interface DatePickerProps {
  /** Selected date */
  value?: Date | null
  /** Date format string for display */
  format?: string
  /** Placeholder text */
  placeholder?: string
  /** Minimum selectable date */
  minDate?: Date
  /** Maximum selectable date */
  maxDate?: Date
  /** Dates that cannot be selected */
  disabledDates?: Date[] | ((date: Date) => boolean)
  /** First day of the week: 0 = Sunday, 1 = Monday */
  weekStart?: 0 | 1
  /** Locale for date formatting */
  locale?: string
  /** Additional class name */
  className?: string
  /** Callback when date is selected or cleared */
  onChange?: (date: Date | null) => void
}

export interface DateRangePreset {
  label: string
  getRange: () => [Date, Date]
}

export interface DateRangePickerProps {
  /** Range start date */
  startDate?: Date | null
  /** Range end date */
  endDate?: Date | null
  /** Date format string for display */
  format?: string
  /** Preset range options */
  presets?: DateRangePreset[]
  /** Minimum selectable date */
  minDate?: Date
  /** Maximum selectable date */
  maxDate?: Date
  /** Locale for date formatting */
  locale?: string
  /** Additional class name */
  className?: string
  /** Callback when range changes */
  onChange?: (start: Date | null, end: Date | null) => void
}

export interface DateTimePickerProps extends Omit<DatePickerProps, 'onChange'> {
  /** Whether to use 24-hour format */
  use24Hour?: boolean
  /** Callback when date or time changes */
  onChange?: (date: Date | null) => void
}

function formatDate(date: Date, format: string, locale?: string): string {
  if (format === 'YYYY-MM-DD') {
    return date.toISOString().split('T')[0] ?? ''
  }
  const loc = locale ?? (typeof navigator !== 'undefined' ? navigator.language : 'en-US')
  return new Intl.DateTimeFormat(loc, {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
  }).format(date)
}

function parseDate(str: string): Date | null {
  const clean = str.trim()
  if (clean === '') return null
  const digits = clean.replace(/\D/g, '')
  if (digits.length >= 8) {
    const year = parseInt(digits.substring(0, 4), 10)
    const month = parseInt(digits.substring(4, 6), 10)
    const day = parseInt(digits.substring(6, 8), 10)
    if (!isNaN(year) && month >= 1 && month <= 12 && day >= 1 && day <= 31) {
      const result = new Date(year, month - 1, day)
      if (!isNaN(result.getTime())) return result
    }
  }
  const parsed = new Date(clean)
  if (!isNaN(parsed.getTime())) return parsed
  return null
}

const CalendarIcon = () => (
  <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
    <rect x="2" y="3" width="12" height="11" rx="1.5" stroke="currentColor" strokeWidth="1.2" />
    <path
      d="M2 6.5h12M5.5 2v2M10.5 2v2"
      stroke="currentColor"
      strokeWidth="1.2"
      strokeLinecap="round"
    />
  </svg>
)

const ClearIcon = () => (
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
    <path
      d="M10.5 3.5L3.5 10.5M3.5 3.5L10.5 10.5"
      stroke="currentColor"
      strokeWidth="1.5"
      strokeLinecap="round"
    />
  </svg>
)

// --- DatePicker ---

function DatePicker({
  value,
  format = 'YYYY-MM-DD',
  placeholder,
  minDate,
  maxDate,
  disabledDates,
  weekStart,
  locale,
  className,
  onChange,
}: DatePickerProps) {
  const [isOpen, setIsOpen] = React.useState(false)
  const [inputValue, setInputValue] = React.useState(value ? formatDate(value, format, locale) : '')
  const rootRef = React.useRef<HTMLDivElement>(null)

  React.useEffect(() => {
    setInputValue(value ? formatDate(value, format, locale) : '')
  }, [value, format, locale])

  // Close on outside click
  React.useEffect(() => {
    if (!isOpen) return
    function handleClick(e: MouseEvent) {
      if (rootRef.current && !rootRef.current.contains(e.target as Node)) {
        setIsOpen(false)
      }
    }
    document.addEventListener('mousedown', handleClick)
    return () => document.removeEventListener('mousedown', handleClick)
  }, [isOpen])

  function handleInputCommit() {
    const parsed = parseDate(inputValue)
    if (parsed) {
      setInputValue(formatDate(parsed, format, locale))
      onChange?.(parsed)
    }
  }

  function handleCalendarChange(date: Date) {
    setInputValue(formatDate(date, format, locale))
    onChange?.(date)
    setIsOpen(false)
  }

  function handleClear(e: React.MouseEvent) {
    e.stopPropagation()
    setInputValue('')
    onChange?.(null)
  }

  return (
    <div
      ref={rootRef}
      data-slot="date-picker"
      className={cn('relative inline-block w-full', className)}
    >
      <div className="relative flex items-center">
        <input
          type="text"
          role="combobox"
          aria-haspopup="dialog"
          aria-expanded={isOpen}
          aria-label="Date"
          autoComplete="off"
          placeholder={placeholder ?? format.toLowerCase()}
          className={cn(
            'border-border-glass bg-glass text-foreground h-10 w-full rounded-xl border px-4 pr-20 py-2 text-[13px] backdrop-blur-[20px]',
            'placeholder:text-foreground-muted',
            'transition-all duration-[250ms] outline-none',
            'focus:border-primary focus:shadow-glow'
          )}
          value={inputValue}
          onChange={e => setInputValue(e.target.value)}
          onBlur={handleInputCommit}
          onKeyDown={e => {
            if (e.key === 'Enter') handleInputCommit()
            if (e.key === 'Escape' && isOpen) {
              e.preventDefault()
              setIsOpen(false)
            }
            if (e.key === 'ArrowDown' && !isOpen) {
              e.preventDefault()
              setIsOpen(true)
            }
          }}
          onFocus={() => setIsOpen(true)}
        />
        <div className="absolute right-1 flex items-center gap-0.5">
          {inputValue && (
            <button
              type="button"
              aria-label="Clear date"
              onClick={handleClear}
              className="inline-flex h-8 w-8 items-center justify-center rounded-lg text-foreground-muted transition-colors hover:text-foreground"
            >
              <ClearIcon />
            </button>
          )}
          <button
            type="button"
            aria-label="Open calendar"
            onClick={() => setIsOpen(o => !o)}
            className="inline-flex h-8 w-8 items-center justify-center rounded-lg text-foreground-muted transition-colors hover:text-foreground"
          >
            <CalendarIcon />
          </button>
        </div>
      </div>

      {isOpen && (
        <div
          role="dialog"
          aria-modal="false"
          aria-label="Choose date"
          className={cn(
            'absolute left-0 z-50 mt-2 rounded-xl border border-border-glass bg-glass p-3 shadow-lg backdrop-blur-[20px]',
            'animate-in fade-in-0 zoom-in-95 slide-in-from-top-2'
          )}
        >
          <Calendar
            value={value}
            mode="single"
            {...(minDate !== undefined ? { minDate } : {})}
            {...(maxDate !== undefined ? { maxDate } : {})}
            {...(disabledDates !== undefined ? { disabledDates } : {})}
            {...(weekStart !== undefined ? { weekStart } : {})}
            onChange={handleCalendarChange}
          />
        </div>
      )}
    </div>
  )
}

// --- DateRangePicker ---

function defaultPresets(): DateRangePreset[] {
  return [
    {
      label: 'Last 7 days',
      getRange: () => {
        const end = new Date()
        const start = new Date()
        start.setDate(start.getDate() - 6)
        return [start, end]
      },
    },
    {
      label: 'Last 30 days',
      getRange: () => {
        const end = new Date()
        const start = new Date()
        start.setDate(start.getDate() - 29)
        return [start, end]
      },
    },
    {
      label: 'Last 90 days',
      getRange: () => {
        const end = new Date()
        const start = new Date()
        start.setDate(start.getDate() - 89)
        return [start, end]
      },
    },
    {
      label: 'Year to date',
      getRange: () => {
        const end = new Date()
        const start = new Date(end.getFullYear(), 0, 1)
        return [start, end]
      },
    },
  ]
}

function DateRangePicker({
  startDate,
  endDate,
  format = 'YYYY-MM-DD',
  presets,
  minDate,
  maxDate,
  locale,
  className,
  onChange,
}: DateRangePickerProps) {
  const [isOpen, setIsOpen] = React.useState(false)
  const [pendingStart, setPendingStart] = React.useState<Date | null>(startDate ?? null)
  const [pendingEnd, setPendingEnd] = React.useState<Date | null>(endDate ?? null)
  const rootRef = React.useRef<HTMLDivElement>(null)

  React.useEffect(() => {
    setPendingStart(startDate ?? null)
    setPendingEnd(endDate ?? null)
  }, [startDate, endDate])

  // Close on outside click
  React.useEffect(() => {
    if (!isOpen) return
    function handleClick(e: MouseEvent) {
      if (rootRef.current && !rootRef.current.contains(e.target as Node)) {
        setIsOpen(false)
      }
    }
    document.addEventListener('mousedown', handleClick)
    return () => document.removeEventListener('mousedown', handleClick)
  }, [isOpen])

  const displayValue = React.useMemo(() => {
    if (startDate && endDate)
      return `${formatDate(startDate, format, locale)} \u2014 ${formatDate(endDate, format, locale)}`
    if (startDate) return `${formatDate(startDate, format, locale)} \u2014 ...`
    return ''
  }, [startDate, endDate, format, locale])

  const presetList = presets ?? defaultPresets()

  function handleOpen() {
    setPendingStart(startDate ?? null)
    setPendingEnd(endDate ?? null)
    setIsOpen(true)
  }

  function handleApply() {
    onChange?.(pendingStart, pendingEnd)
    setIsOpen(false)
  }

  function handlePreset(preset: DateRangePreset) {
    const [start, end] = preset.getRange()
    setPendingStart(start)
    setPendingEnd(end)
  }

  const sharedCalendarProps = {
    mode: 'range' as const,
    rangeStart: pendingStart,
    rangeEnd: pendingEnd,
    ...(minDate !== undefined ? { minDate } : {}),
    ...(maxDate !== undefined ? { maxDate } : {}),
    onRangeChange: (start: Date | null, end: Date | null) => {
      setPendingStart(start)
      setPendingEnd(end)
    },
  }

  return (
    <div
      ref={rootRef}
      data-slot="date-range-picker"
      className={cn('relative inline-block w-full', className)}
    >
      <div className="relative flex items-center">
        <input
          type="text"
          readOnly
          role="combobox"
          aria-haspopup="dialog"
          aria-expanded={isOpen}
          aria-label="Date range"
          placeholder="Select date range"
          className={cn(
            'border-border-glass bg-glass text-foreground h-10 w-full cursor-pointer rounded-xl border px-4 pr-12 py-2 text-[13px] backdrop-blur-[20px]',
            'placeholder:text-foreground-muted',
            'transition-all duration-[250ms] outline-none',
            'focus:border-primary focus:shadow-glow'
          )}
          value={displayValue}
          onClick={() => (isOpen ? setIsOpen(false) : handleOpen())}
          onKeyDown={e => {
            if (e.key === 'Escape' && isOpen) {
              e.preventDefault()
              setIsOpen(false)
            }
          }}
        />
        <button
          type="button"
          aria-label="Open date range picker"
          onClick={e => {
            e.stopPropagation()
            if (isOpen) {
              setIsOpen(false)
            } else {
              handleOpen()
            }
          }}
          className="absolute right-2 inline-flex h-8 w-8 items-center justify-center rounded-lg text-foreground-muted transition-colors hover:text-foreground"
        >
          <CalendarIcon />
        </button>
      </div>

      {isOpen && (
        <div
          role="dialog"
          aria-modal="false"
          aria-label="Choose date range"
          className={cn(
            'absolute left-0 z-50 mt-2 rounded-xl border border-border-glass bg-glass p-4 shadow-lg backdrop-blur-[20px]',
            'animate-in fade-in-0 zoom-in-95 slide-in-from-top-2'
          )}
        >
          <div className="flex gap-4">
            {/* Presets sidebar */}
            <div className="flex min-w-[140px] flex-col gap-1">
              {presetList.map(preset => (
                <button
                  key={preset.label}
                  type="button"
                  className={cn(
                    'rounded-lg px-3 py-2 text-left text-[12px] transition-all duration-200',
                    'text-foreground-secondary hover:bg-glass-hover hover:text-foreground'
                  )}
                  onClick={() => handlePreset(preset)}
                >
                  {preset.label}
                </button>
              ))}
            </div>

            {/* Calendars */}
            <div className="flex gap-4">
              <Calendar {...sharedCalendarProps} />
              <Calendar {...sharedCalendarProps} />
            </div>
          </div>

          {/* Footer */}
          <div className="mt-3 flex justify-end gap-2 border-t border-border-glass pt-3">
            <button
              type="button"
              className={cn(
                'rounded-xl px-4 py-2 text-[13px] transition-all duration-200',
                'text-foreground-secondary hover:bg-glass-hover hover:text-foreground'
              )}
              onClick={() => setIsOpen(false)}
            >
              Cancel
            </button>
            <button
              type="button"
              className={cn(
                'rounded-xl bg-primary px-4 py-2 text-[13px] font-medium text-white shadow-glow transition-all duration-200',
                'hover:brightness-110'
              )}
              onClick={handleApply}
            >
              Apply
            </button>
          </div>
        </div>
      )}
    </div>
  )
}

// --- DateTimePicker ---

function padTwo(n: number): string {
  return String(n).padStart(2, '0')
}

function DateTimePicker({
  value,
  format = 'YYYY-MM-DD',
  placeholder,
  minDate,
  maxDate,
  disabledDates,
  weekStart,
  locale,
  use24Hour = false,
  className,
  onChange,
}: DateTimePickerProps) {
  const [isOpen, setIsOpen] = React.useState(false)
  const [selectedDate, setSelectedDate] = React.useState<Date | null>(value ?? null)
  const [hours, setHours] = React.useState(value ? value.getHours() : 0)
  const [minutes, setMinutes] = React.useState(value ? value.getMinutes() : 0)
  const rootRef = React.useRef<HTMLDivElement>(null)

  React.useEffect(() => {
    setSelectedDate(value ?? null)
    if (value) {
      setHours(value.getHours())
      setMinutes(value.getMinutes())
    }
  }, [value])

  // Close on outside click
  React.useEffect(() => {
    if (!isOpen) return
    function handleClick(e: MouseEvent) {
      if (rootRef.current && !rootRef.current.contains(e.target as Node)) {
        setIsOpen(false)
      }
    }
    document.addEventListener('mousedown', handleClick)
    return () => document.removeEventListener('mousedown', handleClick)
  }, [isOpen])

  function emitChange(date: Date | null, h: number, m: number) {
    if (!date) {
      onChange?.(null)
      return
    }
    const combined = new Date(date.getFullYear(), date.getMonth(), date.getDate(), h, m, 0)
    onChange?.(combined)
  }

  function handleCalendarChange(date: Date) {
    setSelectedDate(date)
    emitChange(date, hours, minutes)
  }

  function handleHourChange(e: React.ChangeEvent<HTMLInputElement>) {
    const v = parseInt(e.target.value, 10)
    const max = use24Hour ? 23 : 12
    const min = use24Hour ? 0 : 1
    if (!isNaN(v) && v >= min && v <= max) {
      setHours(v)
      emitChange(selectedDate, v, minutes)
    }
  }

  function handleMinuteChange(e: React.ChangeEvent<HTMLInputElement>) {
    const v = parseInt(e.target.value, 10)
    if (!isNaN(v) && v >= 0 && v <= 59) {
      setMinutes(v)
      emitChange(selectedDate, hours, v)
    }
  }

  const displayValue = React.useMemo(() => {
    if (!selectedDate) return ''
    const dateStr = formatDate(selectedDate, format, locale)
    const timeStr = `${padTwo(hours)}:${padTwo(minutes)}`
    return `${dateStr} ${timeStr}`
  }, [selectedDate, hours, minutes, format, locale])

  const timeInputClass = cn(
    'border-border-glass bg-glass h-8 w-14 rounded-lg border px-2 text-center text-[13px] text-foreground',
    'outline-none transition-all duration-200 focus:border-primary focus:shadow-glow backdrop-blur-[20px]'
  )

  return (
    <div
      ref={rootRef}
      data-slot="date-time-picker"
      className={cn('relative inline-block w-full', className)}
    >
      <div className="relative flex items-center">
        <input
          type="text"
          readOnly
          role="combobox"
          aria-haspopup="dialog"
          aria-expanded={isOpen}
          aria-label="Date and time"
          placeholder={placeholder ?? `${format.toLowerCase()} hh:mm`}
          className={cn(
            'border-border-glass bg-glass text-foreground h-10 w-full cursor-pointer rounded-xl border px-4 pr-12 py-2 text-[13px] backdrop-blur-[20px]',
            'placeholder:text-foreground-muted',
            'transition-all duration-[250ms] outline-none',
            'focus:border-primary focus:shadow-glow'
          )}
          value={displayValue}
          onClick={() => setIsOpen(o => !o)}
          onKeyDown={e => {
            if (e.key === 'Escape' && isOpen) {
              e.preventDefault()
              setIsOpen(false)
            }
          }}
        />
        <button
          type="button"
          aria-label="Open date time picker"
          onClick={e => {
            e.stopPropagation()
            setIsOpen(o => !o)
          }}
          className="absolute right-2 inline-flex h-8 w-8 items-center justify-center rounded-lg text-foreground-muted transition-colors hover:text-foreground"
        >
          <CalendarIcon />
        </button>
      </div>

      {isOpen && (
        <div
          role="dialog"
          aria-modal="false"
          aria-label="Choose date and time"
          className={cn(
            'absolute left-0 z-50 mt-2 rounded-xl border border-border-glass bg-glass p-3 shadow-lg backdrop-blur-[20px]',
            'animate-in fade-in-0 zoom-in-95 slide-in-from-top-2'
          )}
        >
          <Calendar
            value={selectedDate}
            mode="single"
            minDate={minDate}
            maxDate={maxDate}
            disabledDates={disabledDates}
            weekStart={weekStart}
            onChange={handleCalendarChange}
          />

          {/* Time controls */}
          <div className="mt-3 flex items-center justify-center gap-1 border-t border-border-glass pt-3">
            <span className="mr-2 text-[12px] text-foreground-muted">Time</span>
            <input
              type="number"
              aria-label="Hours"
              className={timeInputClass}
              min={use24Hour ? 0 : 1}
              max={use24Hour ? 23 : 12}
              value={padTwo(hours)}
              onChange={handleHourChange}
            />
            <span className="text-foreground-muted" aria-hidden="true">
              :
            </span>
            <input
              type="number"
              aria-label="Minutes"
              className={timeInputClass}
              min={0}
              max={59}
              value={padTwo(minutes)}
              onChange={handleMinuteChange}
            />
          </div>
        </div>
      )}
    </div>
  )
}

export { DatePicker, DateRangePicker, DateTimePicker }
