import { useEffect, useMemo, useRef, useState } from "react";
import { buildMonthCells, toYmd, WEEKDAY_LABELS_SHORT_RU } from "../lib";

const MONTH_NAMES_RU = [
  "Январь",
  "Февраль",
  "Март",
  "Апрель",
  "Май",
  "Июнь",
  "Июль",
  "Август",
  "Сентябрь",
  "Октябрь",
  "Ноябрь",
  "Декабрь",
];

interface DatePickerFieldProps {
  value: string;
  name: string;
  required?: boolean;
  onChange: (value: string) => void;
}

function parseYmd(value: string): { year: number; monthIndex: number; day: number } | null {
  if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
    return null;
  }

  const year = Number(value.slice(0, 4));
  const monthIndex = Number(value.slice(5, 7)) - 1;
  const day = Number(value.slice(8, 10));

  if (!Number.isInteger(year) || !Number.isInteger(monthIndex) || !Number.isInteger(day)) {
    return null;
  }
  if (monthIndex < 0 || monthIndex > 11) {
    return null;
  }

  return { year, monthIndex, day };
}

function getInitialVisibleMonth(value: string): { year: number; monthIndex: number } {
  const parsed = parseYmd(value);
  if (parsed) {
    return { year: parsed.year, monthIndex: parsed.monthIndex };
  }

  const now = new Date();
  return { year: now.getFullYear(), monthIndex: now.getMonth() };
}

export function DatePickerField(props: DatePickerFieldProps): JSX.Element {
  const { value, name, required, onChange } = props;
  const [isOpen, setIsOpen] = useState(false);
  const [visibleMonth, setVisibleMonth] = useState(() => getInitialVisibleMonth(value));
  const rootRef = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    const parsed = parseYmd(value);
    if (!parsed) {
      return;
    }
    setVisibleMonth({ year: parsed.year, monthIndex: parsed.monthIndex });
  }, [value]);

  useEffect(() => {
    if (!isOpen) {
      return;
    }

    function handlePointerDown(event: MouseEvent): void {
      if (rootRef.current?.contains(event.target as Node)) {
        return;
      }
      setIsOpen(false);
    }

    function handleKeyDown(event: KeyboardEvent): void {
      if (event.key === "Escape") {
        setIsOpen(false);
      }
    }

    document.addEventListener("mousedown", handlePointerDown);
    document.addEventListener("keydown", handleKeyDown);
    return () => {
      document.removeEventListener("mousedown", handlePointerDown);
      document.removeEventListener("keydown", handleKeyDown);
    };
  }, [isOpen]);

  const selected = parseYmd(value);
  const todayYmd = toYmd(new Date().getFullYear(), new Date().getMonth(), new Date().getDate());
  const cells = useMemo(
    () => buildMonthCells(visibleMonth.year, visibleMonth.monthIndex),
    [visibleMonth],
  );
  const monthTitle = `${MONTH_NAMES_RU[visibleMonth.monthIndex]} ${visibleMonth.year}`;

  function shiftMonth(delta: number): void {
    setVisibleMonth((prev) => {
      const next = new Date(Date.UTC(prev.year, prev.monthIndex + delta, 1));
      return { year: next.getUTCFullYear(), monthIndex: next.getUTCMonth() };
    });
  }

  return (
    <div className="date-picker" ref={rootRef}>
      <div className="date-picker__control">
        <input
          className="race-form__input date-picker__input"
          type="text"
          inputMode="numeric"
          name={name}
          value={value}
          onChange={(event) => {
            onChange(event.target.value);
          }}
          onFocus={() => setIsOpen(true)}
          placeholder="2026-05-03"
          autoComplete="off"
          required={required}
        />
        <button
          className="date-picker__toggle"
          type="button"
          aria-label="Открыть календарь"
          aria-expanded={isOpen}
          onClick={() => setIsOpen((prev) => !prev)}
        >
          ▾
        </button>
      </div>

      {isOpen ? (
        <div className="date-picker__popover" role="dialog" aria-label="Выбор даты">
          <div className="date-picker__header">
            <button
              className="date-picker__nav"
              type="button"
              aria-label="Предыдущий месяц"
              onClick={() => shiftMonth(-1)}
            >
              ‹
            </button>
            <p className="date-picker__title">{monthTitle}</p>
            <button
              className="date-picker__nav"
              type="button"
              aria-label="Следующий месяц"
              onClick={() => shiftMonth(1)}
            >
              ›
            </button>
          </div>
          <div className="date-picker__weekdays" aria-hidden>
            {WEEKDAY_LABELS_SHORT_RU.map((weekday) => (
              <span key={weekday} className="date-picker__weekday">
                {weekday}
              </span>
            ))}
          </div>
          <div className="date-picker__cells">
            {cells.map((day, idx) => {
              if (day === null) {
                return <span key={`empty-${idx}`} className="date-picker__cell date-picker__cell--empty" />;
              }

              const ymd = toYmd(visibleMonth.year, visibleMonth.monthIndex, day);
              const isSelected =
                selected?.year === visibleMonth.year &&
                selected.monthIndex === visibleMonth.monthIndex &&
                selected.day === day;

              return (
                <button
                  key={ymd}
                  className={`date-picker__day${isSelected ? " date-picker__day--selected" : ""}${ymd === todayYmd ? " date-picker__day--today" : ""}`}
                  type="button"
                  onClick={() => {
                    onChange(ymd);
                    setIsOpen(false);
                  }}
                >
                  {day}
                </button>
              );
            })}
          </div>
        </div>
      ) : null}
    </div>
  );
}
