/**
 * DatePicker — 日期选择器
 * @prop {'date'|'datetime'|'daterange'|'datetimerange'} [type='date'] — 选择类型
 * @prop {string} value — 当前值（受控）
 * @prop {string} [defaultValue=undefined] — 非受控初始值
 * @prop {string} [placeholder=''] — 占位文案
 * @prop {boolean} [disabled=false] — 是否禁用
 * @prop {boolean} [defaultOpen=false] — 初始是否展开
 * @prop {Function} [onChange=null] — 变更回调
 * @prop {string} [className=''] — 额外类名
 */

import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
import { createPortal } from 'react-dom';

/* ── 布局数值 ── */
const PANEL_GAP = 4;
const PANEL_Z = 10000;
const CALENDAR_CELL_SIZE = 36;
const CALENDAR_COLS = 7;
const MONTH_HORIZONTAL_PADDING = 16;
/** 单月历：左右内边距 + 7 列日期格（36px） */
const PANEL_WIDTH_SINGLE = MONTH_HORIZONTAL_PADDING * 2 + CALENDAR_CELL_SIZE * CALENDAR_COLS;
/** 双月历范围：两列单月历并排 */
const PANEL_WIDTH_RANGE = PANEL_WIDTH_SINGLE * 2;

/* ── 星期标签 ── */
const WEEK_LABELS = ['日', '一', '二', '三', '四', '五', '六'];

/* ── 类型映射 ── */
const TYPE_CONFIG = {
  date: {
    widthClass: 'w-full min-w-0 max-w-full',
    placeholder: '请选择日期',
    isRange: false,
    withTime: false,
    panelWidth: PANEL_WIDTH_SINGLE,
    panelHeight: 312,
    footerMode: 'none',
  },
  datetime: {
    widthClass: 'w-full min-w-0 max-w-full',
    placeholder: '请选择日期及时间',
    isRange: false,
    withTime: true,
    panelWidth: PANEL_WIDTH_SINGLE,
    panelHeight: 348,
    footerMode: 'datetime-single',
  },
  daterange: {
    widthClass: 'w-full min-w-0 max-w-full',
    placeholderStart: '开始日期',
    placeholderEnd: '结束日期',
    isRange: true,
    withTime: false,
    panelWidth: PANEL_WIDTH_RANGE,
    panelHeight: 312,
    footerMode: 'none',
  },
  datetimerange: {
    widthClass: 'w-full min-w-0 max-w-full',
    placeholderStart: '开始日期',
    placeholderEnd: '结束日期',
    isRange: true,
    withTime: true,
    panelWidth: PANEL_WIDTH_RANGE,
    panelHeight: 348,
    footerMode: 'datetime-range',
  },
};

/* ── Trigger 样式 ── */
const FRAME_BASE = [
  'relative inline-flex items-center',
  'h-[36px]',
  'border border-solid border-border-default',
  'rounded-md',
  'transition-colors tfds-motion-ui-fast',
  '[font-family:inherit]',
  'outline-none',
  'cursor-pointer',
].join(' ');

const SINGLE_FRAME = [
  'bg-surface',
  'pl-3 pr-2',
  'gap-2',
  'hover:border-border-strong',
  'focus-within:border-primary',
  'focus-within:hover:border-primary',
].join(' ');

const RANGE_FRAME = [
  'bg-surface',
  'pl-3 pr-2',
  'gap-2',
  'hover:border-border-strong',
  'focus-within:border-primary',
  'focus-within:hover:border-primary',
].join(' ');

const DISABLED_CLASS = [
  'bg-disabled',
  'border-border-default',
  'cursor-not-allowed',
  'opacity-60',
  'pointer-events-none',
].join(' ');

const TEXT_BASE = 'text-sm leading-[20px]';
const VALUE_TEXT = [TEXT_BASE, 'text-foreground truncate'].join(' ');
const PLACEHOLDER_TEXT = [TEXT_BASE, 'text-foreground-muted truncate'].join(' ');
const RANGE_SEP = [TEXT_BASE, 'text-foreground-muted shrink-0'].join(' ');
const CONTENT_SLOT = 'min-w-0 flex-1';
const ICON_SLOT = 'inline-flex size-[16px] shrink-0 items-center justify-center text-foreground-disabled [&>svg]:size-[16px]';

/* ── Panel 样式 ── */
const PANEL_BASE = [
  'overflow-hidden rounded-[6px]',
  'border border-solid border-border-default',
  'bg-surface',
  'shadow-[0_4px_14px_rgba(0,0,0,0.1)]',
].join(' ');

const MONTH_SHELL = 'min-w-[284px] shrink-0 px-[16px] pt-[12px] pb-[16px]';
const MONTH_HEADER = 'flex h-[32px] items-center justify-between';
const MONTH_TITLE = 'text-[14px] leading-[20px] [font-weight:var(--font-semibold)] text-foreground';
const NAV_BTN = [
  'inline-flex size-[20px] items-center justify-center',
  'rounded-[3px] bg-transparent border-none p-0',
  'text-foreground-secondary',
  'hover:bg-fill',
  'transition-colors tfds-motion-ui-instant',
].join(' ');
const WEEK_GRID = 'mt-[8px] grid grid-cols-[repeat(7,36px)] justify-center';
const WEEK_CELL = 'flex size-[36px] items-center justify-center text-center text-[12px] leading-[16px] [font-weight:var(--font-semibold)] text-foreground-muted';
const DAY_GRID = 'grid grid-cols-[repeat(7,36px)] justify-center';
const DAY_CELL = 'flex size-[36px] items-center justify-center p-0 border-none bg-transparent';
const DAY_INNER = 'mx-[2px] my-[2px] size-[32px] flex items-center justify-center text-[14px] leading-[20px] transition-colors tfds-motion-ui-instant';

const FOOTER_BASE = [
  'h-[52px] border-t border-solid border-t-border',
  'text-[14px] leading-[20px]',
].join(' ');
const FOOTER_CELL = 'flex min-w-0 items-center gap-[4px] pl-[18px]';
const FOOTER_ICON = 'inline-flex size-[16px] shrink-0 items-center justify-center text-foreground-secondary';
const FOOTER_DATE = 'truncate [font-weight:var(--font-semibold)] text-foreground';
const FOOTER_TIME = 'truncate text-foreground-muted';

function pad2(n) {
  return String(n).padStart(2, '0');
}

function startOfDay(date) {
  const d = new Date(date);
  d.setHours(0, 0, 0, 0);
  return d;
}

function startOfMonth(date) {
  return new Date(date.getFullYear(), date.getMonth(), 1);
}

function addMonths(date, n) {
  return new Date(date.getFullYear(), date.getMonth() + n, 1);
}

function isSameDay(a, b) {
  return a.getFullYear() === b.getFullYear()
    && a.getMonth() === b.getMonth()
    && a.getDate() === b.getDate();
}

function parseDateLike(raw) {
  if (raw == null || raw === '') return null;
  if (raw instanceof Date && !Number.isNaN(raw.getTime())) return new Date(raw);
  if (typeof raw === 'number') {
    const d = new Date(raw);
    return Number.isNaN(d.getTime()) ? null : d;
  }
  if (typeof raw === 'string') {
    const d = new Date(raw.trim());
    return Number.isNaN(d.getTime()) ? null : d;
  }
  return null;
}

function parseTimePart(raw) {
  if (typeof raw !== 'string') return null;
  const match = raw.match(/(\d{2}:\d{2}:\d{2})/);
  return match ? match[1] : null;
}

function applyTime(date, timeText) {
  const d = new Date(date);
  if (!timeText) {
    d.setHours(0, 0, 0, 0);
    return d;
  }
  const [h, m, s] = timeText.split(':').map((v) => Number(v || 0));
  d.setHours(h, m, s, 0);
  return d;
}

function formatDateByType(date, withTime) {
  const y = date.getFullYear();
  const m = pad2(date.getMonth() + 1);
  const d = pad2(date.getDate());
  if (!withTime) return `${y}-${m}-${d}`;
  const hh = pad2(date.getHours());
  const mm = pad2(date.getMinutes());
  const ss = pad2(date.getSeconds());
  return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
}

function formatMonthLabel(date) {
  return `${date.getFullYear()} 年 ${date.getMonth() + 1} 月`;
}

function createMonthCells(monthDate) {
  const year = monthDate.getFullYear();
  const month = monthDate.getMonth();
  const daysInMonth = new Date(year, month + 1, 0).getDate();
  const firstWeekday = new Date(year, month, 1).getDay();

  const cells = [];
  for (let i = 0; i < 42; i += 1) {
    const day = i - firstWeekday + 1;
    if (day < 1 || day > daysInMonth) {
      cells.push(null);
    } else {
      cells.push(new Date(year, month, day));
    }
  }
  return cells;
}

function compareDay(a, b) {
  return startOfDay(a).getTime() - startOfDay(b).getTime();
}

function normalizeValue(raw, config) {
  if (!config.isRange) {
    const parsed = parseDateLike(raw);
    if (!parsed) return null;
    if (!config.withTime) return applyTime(parsed, null);
    const fallbackTime = parseTimePart(typeof raw === 'string' ? raw : '') || '16:00:00';
    return applyTime(parsed, fallbackTime);
  }

  if (!Array.isArray(raw)) return [null, null];
  const [s, e] = raw;
  const startDate = parseDateLike(s);
  const endDate = parseDateLike(e);

  if (!config.withTime) {
    return [
      startDate ? applyTime(startDate, null) : null,
      endDate ? applyTime(endDate, null) : null,
    ];
  }

  const startTime = parseTimePart(typeof s === 'string' ? s : '') || '09:00:00';
  const endTime = parseTimePart(typeof e === 'string' ? e : '') || '16:00:00';

  return [
    startDate ? applyTime(startDate, startTime) : null,
    endDate ? applyTime(endDate, endTime) : null,
  ];
}

function ChevronLeftIcon() {
  return (
    <svg viewBox="0 0 16 16" fill="none" className="size-[16px]" aria-hidden="true">
      <path d="M10 3.5L5.5 8L10 12.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

function ChevronRightIcon() {
  return (
    <svg viewBox="0 0 16 16" fill="none" className="size-[16px]" aria-hidden="true">
      <path d="M6 3.5L10.5 8L6 12.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

function CalendarIcon({ withTime = false }) {
  return (
    <svg viewBox="0 0 16 16" fill="none" className="size-[16px]" aria-hidden="true">
      <rect x="2.5" y="3.5" width="11" height="10" rx="1.5" stroke="currentColor" strokeWidth="1.2" />
      <path d="M5.5 2.5V5M10.5 2.5V5M2.5 6.5H13.5" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" />
      {withTime ? (
        <>
          <circle cx="11.2" cy="10.9" r="2.2" fill="var(--color-surface)" />
          <circle cx="11.2" cy="10.9" r="1.7" stroke="currentColor" strokeWidth="1.1" />
          <path d="M11.2 9.9V10.9L11.9 11.4" stroke="currentColor" strokeWidth="1.1" strokeLinecap="round" strokeLinejoin="round" />
        </>
      ) : (
        <rect x="9.2" y="8.6" width="2.2" height="2.2" rx="0.4" fill="currentColor" />
      )}
    </svg>
  );
}

function ClockIcon() {
  return (
    <svg viewBox="0 0 16 16" fill="none" className="size-[16px]" aria-hidden="true">
      <circle cx="8" cy="8" r="5.5" stroke="currentColor" strokeWidth="1.2" />
      <path d="M8 5.4V8L9.8 9" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

function MonthPanel({
  monthDate,
  onPrev,
  onNext,
  showPrev,
  showNext,
  mode,
  selectedDate,
  rangeStart,
  rangeEnd,
  onPick,
  today,
}) {
  const cells = useMemo(() => createMonthCells(monthDate), [monthDate]);

  return (
    <div className={MONTH_SHELL}>
      <div className={MONTH_HEADER}>
        {showPrev ? (
          <button type="button" className={NAV_BTN} onClick={onPrev} aria-label="上个月">
            <ChevronLeftIcon />
          </button>
        ) : <span className="inline-flex size-[20px]" />}

        <span className={MONTH_TITLE}>{formatMonthLabel(monthDate)}</span>

        {showNext ? (
          <button type="button" className={NAV_BTN} onClick={onNext} aria-label="下个月">
            <ChevronRightIcon />
          </button>
        ) : <span className="inline-flex size-[20px]" />}
      </div>

      <div className={WEEK_GRID}>
        {WEEK_LABELS.map((label) => (
          <div key={label} className={WEEK_CELL}>{label}</div>
        ))}
      </div>

      <div className={DAY_GRID}>
        {cells.map((day, idx) => {
          if (!day) return <div key={idx} className="size-[36px]" />;

          const isToday = isSameDay(day, today);
          const isSelectedSingle = mode === 'single' && selectedDate && isSameDay(day, selectedDate);
          const isStart = mode === 'range' && rangeStart && isSameDay(day, rangeStart);
          const isEnd = mode === 'range' && rangeEnd && isSameDay(day, rangeEnd);
          const isSameStartEnd = Boolean(isStart && isEnd);

          let inRange = false;
          if (mode === 'range' && rangeStart && rangeEnd) {
            inRange = compareDay(day, rangeStart) >= 0 && compareDay(day, rangeEnd) <= 0;
          }

          const inner = [DAY_INNER];

          if (isSelectedSingle || isStart || isEnd) {
            inner.push('bg-primary text-foreground-inverse');
            if (mode === 'range' && !isSameStartEnd && rangeStart && rangeEnd) {
              if (isStart) {
                inner.push('rounded-l-[3px] rounded-r-none');
              } else if (isEnd) {
                inner.push('rounded-r-[3px] rounded-l-none');
              }
            } else {
              inner.push('rounded-[3px]');
            }
          } else if (inRange) {
            inner.push('bg-brand-50 text-foreground rounded-none');
          } else if (isToday) {
            inner.push('bg-[rgba(52,59,58,0.05)] text-primary [font-weight:var(--font-semibold)] rounded-[3px]');
          } else {
            inner.push('text-foreground rounded-[3px] hover:bg-fill');
          }

          return (
            <button
              key={idx}
              type="button"
              className={DAY_CELL}
              onClick={() => onPick(day)}
              aria-label={formatDateByType(day, false)}
            >
              <span className={inner.join(' ')}>{day.getDate()}</span>
            </button>
          );
        })}
      </div>
    </div>
  );
}

function measurePanel(triggerEl, panelWidth, panelHeight) {
  const rect = triggerEl.getBoundingClientRect();
  const spaceBelow = window.innerHeight - rect.bottom - PANEL_GAP;
  const spaceAbove = rect.top - PANEL_GAP;
  const placeBelow = spaceBelow >= panelHeight || spaceBelow >= spaceAbove;

  const top = placeBelow
    ? rect.bottom + PANEL_GAP
    : Math.max(8, rect.top - panelHeight - PANEL_GAP);

  let left = rect.left;
  if (left + panelWidth > window.innerWidth - 8) {
    left = Math.max(8, window.innerWidth - panelWidth - 8);
  }

  return { top, left, width: panelWidth };
}

export default function DatePicker({
  type = 'date',
  value,
  defaultValue,
  placeholder,
  disabled = false,
  defaultOpen = false,
  onChange,
  className = '',
  ...rest
}) {
  const config = TYPE_CONFIG[type] || TYPE_CONFIG.date;
  const isControlled = value !== undefined;
  const [innerValue, setInnerValue] = useState(defaultValue);
  const currentRawValue = isControlled ? value : innerValue;

  const normalizedValue = useMemo(() => normalizeValue(currentRawValue, config), [currentRawValue, config]);

  const [open, setOpen] = useState(Boolean(defaultOpen) && !disabled);
  const [panelPos, setPanelPos] = useState({ top: 0, left: 0, width: PANEL_WIDTH_SINGLE });

  const triggerRef = useRef(null);
  const panelRef = useRef(null);
  const today = useMemo(() => startOfDay(new Date()), []);

  const initialMonth = useMemo(() => {
    if (!config.isRange) {
      return normalizedValue ? startOfMonth(normalizedValue) : startOfMonth(new Date());
    }
    const [start] = normalizedValue;
    return start ? startOfMonth(start) : startOfMonth(new Date());
  }, [config.isRange, normalizedValue]);

  const [leftMonth, setLeftMonth] = useState(initialMonth);

  useEffect(() => {
    setLeftMonth(initialMonth);
  }, [initialMonth]);

  const updatePanelPos = useCallback(() => {
    if (!triggerRef.current) return;
    setPanelPos(measurePanel(triggerRef.current, config.panelWidth, config.panelHeight));
  }, [config.panelHeight, config.panelWidth]);

  useLayoutEffect(() => {
    if (!open) return;
    updatePanelPos();
  }, [open, updatePanelPos]);

  useEffect(() => {
    if (!open) return;
    let frameId = 0;
    const startedAt = performance.now();
    const syncDuringPreviewMotion = () => {
      updatePanelPos();
      if (performance.now() - startedAt < 260) {
        frameId = window.requestAnimationFrame(syncDuringPreviewMotion);
      }
    };
    frameId = window.requestAnimationFrame(syncDuringPreviewMotion);
    return () => window.cancelAnimationFrame(frameId);
  }, [open, updatePanelPos]);

  useEffect(() => {
    if (!open) return;
    const onMove = () => updatePanelPos();
    window.addEventListener('resize', onMove);
    window.addEventListener('scroll', onMove, true);
    return () => {
      window.removeEventListener('resize', onMove);
      window.removeEventListener('scroll', onMove, true);
    };
  }, [open, updatePanelPos]);

  useEffect(() => {
    if (!open) return;
    const onDown = (e) => {
      const t = e.target;
      if (triggerRef.current?.contains(t) || panelRef.current?.contains(t)) return;
      setOpen(false);
    };
    const onKey = (e) => {
      if (e.key === 'Escape') setOpen(false);
    };
    document.addEventListener('mousedown', onDown);
    document.addEventListener('keydown', onKey);
    return () => {
      document.removeEventListener('mousedown', onDown);
      document.removeEventListener('keydown', onKey);
    };
  }, [open]);

  const commitValue = useCallback((nextVal, payload) => {
    if (!isControlled) setInnerValue(nextVal);
    onChange?.(...payload);
  }, [isControlled, onChange]);

  const pickSingle = useCallback((day) => {
    if (!config.withTime) {
      const next = applyTime(day, null);
      commitValue(next, [next, formatDateByType(next, false)]);
      setOpen(false);
      return;
    }

    const currentTime = normalizedValue ? `${pad2(normalizedValue.getHours())}:${pad2(normalizedValue.getMinutes())}:${pad2(normalizedValue.getSeconds())}` : '16:00:00';
    const next = applyTime(day, currentTime);
    commitValue(next, [next, formatDateByType(next, true)]);
    setOpen(false);
  }, [config.withTime, normalizedValue, commitValue]);

  const pickRange = useCallback((day) => {
    const [rawStart, rawEnd] = normalizedValue;

    const defaultStartTime = config.withTime
      ? (rawStart ? `${pad2(rawStart.getHours())}:${pad2(rawStart.getMinutes())}:${pad2(rawStart.getSeconds())}` : '09:00:00')
      : null;
    const defaultEndTime = config.withTime
      ? (rawEnd ? `${pad2(rawEnd.getHours())}:${pad2(rawEnd.getMinutes())}:${pad2(rawEnd.getSeconds())}` : '16:00:00')
      : null;

    const currentDay = applyTime(day, config.withTime ? defaultStartTime : null);

    if (!rawStart || (rawStart && rawEnd)) {
      const next = [currentDay, null];
      commitValue(next, [next, [formatDateByType(currentDay, config.withTime), '']]);
      return;
    }

    let start = rawStart;
    let end = applyTime(day, config.withTime ? defaultEndTime : null);

    if (compareDay(end, start) < 0) {
      const swappedStart = applyTime(day, config.withTime ? defaultStartTime : null);
      const swappedEnd = rawStart;
      start = swappedStart;
      end = swappedEnd;
    }

    const next = [start, end];
    commitValue(next, [
      next,
      [formatDateByType(start, config.withTime), formatDateByType(end, config.withTime)],
    ]);
    setOpen(false);
  }, [normalizedValue, config.withTime, commitValue]);

  const triggerClass = [
    FRAME_BASE,
    config.isRange ? RANGE_FRAME : SINGLE_FRAME,
    config.widthClass,
    disabled ? DISABLED_CLASS : '',
    className,
  ].filter(Boolean).join(' ');

  const rightMonth = useMemo(() => addMonths(leftMonth, 1), [leftMonth]);

  let displaySingle = '';
  let displayRangeStart = '';
  let displayRangeEnd = '';

  if (!config.isRange) {
    displaySingle = normalizedValue ? formatDateByType(normalizedValue, config.withTime) : '';
  } else {
    const [start, end] = normalizedValue;
    displayRangeStart = start ? formatDateByType(start, config.withTime) : '';
    displayRangeEnd = end ? formatDateByType(end, config.withTime) : '';
  }

  const singleFooter = config.footerMode === 'datetime-single' && normalizedValue ? (
    <div className={[FOOTER_BASE, 'grid grid-cols-2'].join(' ')}>
      <div className={FOOTER_CELL}>
        <span className={FOOTER_ICON}><CalendarIcon /></span>
        <span className={FOOTER_DATE}>{formatDateByType(normalizedValue, false)}</span>
      </div>
      <div className={FOOTER_CELL}>
        <span className={FOOTER_ICON}><ClockIcon /></span>
        <span className={FOOTER_TIME}>{`${pad2(normalizedValue.getHours())}:${pad2(normalizedValue.getMinutes())}:${pad2(normalizedValue.getSeconds())}`}</span>
      </div>
    </div>
  ) : null;

  const rangeFooter = config.footerMode === 'datetime-range' ? (
    <div className={[FOOTER_BASE, 'grid grid-cols-4'].join(' ')}>
      <div className={FOOTER_CELL}>
        <span className={FOOTER_ICON}><CalendarIcon /></span>
        <span className={FOOTER_DATE}>{displayRangeStart ? displayRangeStart.slice(0, 10) : '开始日期'}</span>
      </div>
      <div className={FOOTER_CELL}>
        <span className={FOOTER_ICON}><ClockIcon /></span>
        <span className={FOOTER_TIME}>{displayRangeStart ? displayRangeStart.slice(11) : '09:00:00'}</span>
      </div>
      <div className={FOOTER_CELL}>
        <span className={FOOTER_ICON}><CalendarIcon /></span>
        <span className={FOOTER_DATE}>{displayRangeEnd ? displayRangeEnd.slice(0, 10) : '结束日期'}</span>
      </div>
      <div className={FOOTER_CELL}>
        <span className={FOOTER_ICON}><ClockIcon /></span>
        <span className={FOOTER_TIME}>{displayRangeEnd ? displayRangeEnd.slice(11) : '16:00:00'}</span>
      </div>
    </div>
  ) : null;

  const panel = open && typeof document !== 'undefined' ? createPortal(
    <div
      ref={panelRef}
      className={PANEL_BASE}
      style={{
        position: 'fixed',
        top: panelPos.top,
        left: panelPos.left,
        width: `${panelPos.width}px`,
        zIndex: PANEL_Z,
      }}
    >
      {!config.isRange ? (
        <>
          <MonthPanel
            monthDate={leftMonth}
            onPrev={() => setLeftMonth((m) => addMonths(m, -1))}
            onNext={() => setLeftMonth((m) => addMonths(m, 1))}
            showPrev
            showNext
            mode="single"
            selectedDate={normalizedValue}
            rangeStart={null}
            rangeEnd={null}
            onPick={pickSingle}
            today={today}
          />
          {singleFooter}
        </>
      ) : (
        <>
          <div className="flex shrink-0">
            <MonthPanel
              monthDate={leftMonth}
              onPrev={() => setLeftMonth((m) => addMonths(m, -1))}
              onNext={() => {}}
              showPrev
              showNext={false}
              mode="range"
              selectedDate={null}
              rangeStart={normalizedValue[0]}
              rangeEnd={normalizedValue[1]}
              onPick={pickRange}
              today={today}
            />
            <MonthPanel
              monthDate={rightMonth}
              onPrev={() => {}}
              onNext={() => setLeftMonth((m) => addMonths(m, 1))}
              showPrev={false}
              showNext
              mode="range"
              selectedDate={null}
              rangeStart={normalizedValue[0]}
              rangeEnd={normalizedValue[1]}
              onPick={pickRange}
              today={today}
            />
          </div>
          {rangeFooter}
        </>
      )}
    </div>,
    document.body,
  ) : null;

  return (
    <>
      {!config.isRange ? (
        <div
          ref={triggerRef}
          className={[`tfds-date-picker`, triggerClass].filter(Boolean).join(' ')}
          tabIndex={disabled ? -1 : 0}
          aria-disabled={disabled}
          role="combobox"
          aria-expanded={open}
          onClick={() => {
            if (disabled) return;
            setOpen((o) => !o);
          }}
          {...rest}
          data-tfds-component="DatePicker"
        >
          <span className={[CONTENT_SLOT, displaySingle ? VALUE_TEXT : PLACEHOLDER_TEXT].join(' ')}>
            {displaySingle || placeholder || config.placeholder}
          </span>
          <span className={ICON_SLOT}><CalendarIcon withTime={config.withTime} /></span>
        </div>
      ) : (
        <div
          ref={triggerRef}
          className={[`tfds-date-picker`, triggerClass].filter(Boolean).join(' ')}
          tabIndex={disabled ? -1 : 0}
          aria-disabled={disabled}
          role="combobox"
          aria-expanded={open}
          onClick={() => {
            if (disabled) return;
            setOpen((o) => !o);
          }}
          {...rest}
          data-tfds-component="DatePicker"
        >
          <span className={[CONTENT_SLOT, displayRangeStart ? VALUE_TEXT : PLACEHOLDER_TEXT].join(' ')}>
            {displayRangeStart || config.placeholderStart}
          </span>
          <span className={RANGE_SEP}>~</span>
          <span className={[CONTENT_SLOT, displayRangeEnd ? VALUE_TEXT : PLACEHOLDER_TEXT].join(' ')}>
            {displayRangeEnd || config.placeholderEnd}
          </span>
          <span className={ICON_SLOT}><CalendarIcon withTime={config.withTime} /></span>
        </div>
      )}
      {panel}
    </>
  );
}

DatePicker.displayName = 'DatePicker';

export { DatePicker };
