import { useMemo, useState } from 'react';
import { format } from 'date-fns';
import ConfigProvider from 'antd/es/config-provider';
import DatePicker from 'antd/es/date-picker';
import zhCN from 'antd/es/locale/zh_CN';
import dayjs, { type Dayjs } from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import 'dayjs/locale/zh-cn';
import { CalendarIcon, X } from 'lucide-react';
import { Button } from './button';
import { Calendar } from './calendar';
import { gatewayAntdTheme } from './antd-theme';
import { Input } from './input';
import { Label } from './label';
import { Popover, PopoverContent, PopoverTrigger } from './popover';

dayjs.extend(customParseFormat);
dayjs.locale('zh-cn');

export function DateTimePicker(props: {
  clearLabel?: string;
  disabled?: boolean;
  placeholder?: string;
  value: string;
  onChange: (value: string) => void;
}) {
  const [open, setOpen] = useState(false);
  const selectedDate = useMemo(() => parseLocalDateTime(props.value), [props.value]);
  const timeValue = selectedDate ? formatTimeValue(selectedDate) : '';

  function updateDate(nextDate: Date | undefined) {
    if (!nextDate) return;
    const current = selectedDate ?? new Date();
    const next = new Date(nextDate);
    next.setHours(current.getHours(), current.getMinutes(), 0, 0);
    props.onChange(formatLocalDateTime(next));
  }

  function updateTime(value: string) {
    const [hours, minutes] = value.split(':').map((item) => Number(item));
    if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return;
    const next = selectedDate ? new Date(selectedDate) : new Date();
    next.setHours(hours, minutes, 0, 0);
    props.onChange(formatLocalDateTime(next));
  }

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <Button
          className="dateTimePickerTrigger"
          data-empty={!selectedDate}
          disabled={props.disabled}
          type="button"
          variant="outline"
        >
          <CalendarIcon size={15} />
          {selectedDate ? format(selectedDate, 'yyyy-MM-dd HH:mm') : <span>{props.placeholder ?? '选择日期时间'}</span>}
        </Button>
      </PopoverTrigger>
      <PopoverContent align="start" className="dateTimePickerPopover">
        <Calendar mode="single" selected={selectedDate} onSelect={updateDate} />
        <div className="dateTimePickerFooter">
          <Label>
            时间
            <Input type="time" value={timeValue} onChange={(event) => updateTime(event.target.value)} />
          </Label>
          <Button type="button" variant="ghost" size="icon" title={props.clearLabel ?? '清除有效期'} disabled={!props.value} onClick={() => props.onChange('')}>
            <X size={14} />
          </Button>
        </div>
      </PopoverContent>
    </Popover>
  );
}

export function DateTimeRangePicker(props: {
  disabled?: boolean;
  from: string;
  fromPlaceholder?: string;
  to: string;
  toPlaceholder?: string;
  onChange: (value: { from: string; to: string }) => void;
}) {
  const value = useMemo<[Dayjs | null, Dayjs | null] | null>(() => {
    const from = parseDayjsDateTime(props.from);
    const to = parseDayjsDateTime(props.to);
    return from || to ? [from, to] : null;
  }, [props.from, props.to]);

  return (
    <ConfigProvider locale={zhCN} theme={gatewayAntdTheme}>
      <DatePicker.RangePicker
        allowClear
        className="shDateRangePicker"
        classNames={{ popup: { root: 'shDateRangePickerPopup' } }}
        disabled={props.disabled}
        format={rangeDateTimeFormat}
        needConfirm
        placeholder={[props.fromPlaceholder ?? '开始日期', props.toPlaceholder ?? '结束日期']}
        showTime={{ format: 'HH:mm:ss' }}
        size="middle"
        style={{ width: '100%' }}
        value={value}
        onChange={(nextValue) => {
          props.onChange({
            from: nextValue?.[0] ? nextValue[0].format(rangeDateTimeFormat) : '',
            to: nextValue?.[1] ? nextValue[1].format(rangeDateTimeFormat) : '',
          });
        }}
      />
    </ConfigProvider>
  );
}

const rangeDateTimeFormat = 'YYYY-MM-DD HH:mm:ss';
const rangeParseFormats = [rangeDateTimeFormat, 'YYYY-MM-DDTHH:mm:ss', 'YYYY-MM-DDTHH:mm', 'YYYY-MM-DD'];
function parseLocalDateTime(value: string) {
  if (!value) return undefined;
  const normalized = value.includes('T') ? value : value.replace(' ', 'T');
  const date = new Date(normalized);
  return Number.isNaN(date.getTime()) ? undefined : date;
}

function formatLocalDateTime(date: Date) {
  const year = date.getFullYear();
  const month = pad(date.getMonth() + 1);
  const day = pad(date.getDate());
  const hours = pad(date.getHours());
  const minutes = pad(date.getMinutes());
  return `${year}-${month}-${day}T${hours}:${minutes}`;
}

function formatTimeValue(date: Date) {
  return `${pad(date.getHours())}:${pad(date.getMinutes())}`;
}

function parseDayjsDateTime(value: string): Dayjs | null {
  if (!value) return null;
  const parsed = dayjs(value, rangeParseFormats, true);
  if (parsed.isValid()) return parsed;
  const fallback = dayjs(value);
  return fallback.isValid() ? fallback : null;
}

function pad(value: number) {
  return String(value).padStart(2, '0');
}
