import {
  useEffect,
  useId,
  useMemo,
  useRef,
  useState,
  type ReactNode,
} from "react";
import { cx } from "./utils";
import { Icon } from "./Icon";
import { Button } from "./Button";

const MONTHS = [
  "janvier", "février", "mars", "avril", "mai", "juin",
  "juillet", "août", "septembre", "octobre", "novembre", "décembre",
];
const WEEKDAYS = ["lun", "mar", "mer", "jeu", "ven", "sam", "dim"];

const fmt = (d: Date | null) =>
  d
    ? d.toLocaleDateString("fr-FR", {
        day: "2-digit",
        month: "2-digit",
        year: "numeric",
      })
    : "";

const sameDay = (a: Date, b: Date) =>
  a.getFullYear() === b.getFullYear() &&
  a.getMonth() === b.getMonth() &&
  a.getDate() === b.getDate();

function buildMonthGrid(year: number, month: number) {
  const first = new Date(year, month, 1);
  // En France lundi = jour 0
  const startDay = (first.getDay() + 6) % 7;
  const daysInMonth = new Date(year, month + 1, 0).getDate();
  const daysInPrev = new Date(year, month, 0).getDate();
  const cells: { date: Date; outside: boolean }[] = [];

  // Préfixe (mois précédent)
  for (let i = startDay - 1; i >= 0; i--) {
    cells.push({ date: new Date(year, month - 1, daysInPrev - i), outside: true });
  }
  for (let d = 1; d <= daysInMonth; d++) {
    cells.push({ date: new Date(year, month, d), outside: false });
  }
  // Suffixe (mois suivant)
  while (cells.length < 42) {
    const idx = cells.length - (startDay + daysInMonth);
    cells.push({ date: new Date(year, month + 1, idx + 1), outside: true });
  }
  return cells;
}

export type DatePickerProps = {
  label?: ReactNode;
  hint?: ReactNode;
  error?: ReactNode;
  value?: Date | null;
  onChange?: (date: Date | null) => void;
  required?: boolean;
  disabled?: boolean;
  /** Désactive certaines dates */
  isDisabled?: (date: Date) => boolean;
  placeholder?: string;
  className?: string;
};

export function DatePicker({
  label,
  hint,
  error,
  value,
  onChange,
  required,
  disabled,
  isDisabled,
  placeholder = "JJ/MM/AAAA",
  className,
}: DatePickerProps) {
  const id = useId();
  const [open, setOpen] = useState(false);
  const [view, setView] = useState(() => value ?? new Date());
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (value) setView(value);
  }, [value]);

  useEffect(() => {
    if (!open) return;
    const onClick = (e: MouseEvent) => {
      if (!ref.current?.contains(e.target as Node)) setOpen(false);
    };
    const onKey = (e: KeyboardEvent) => {
      if (e.key === "Escape") setOpen(false);
    };
    document.addEventListener("mousedown", onClick);
    document.addEventListener("keydown", onKey);
    return () => {
      document.removeEventListener("mousedown", onClick);
      document.removeEventListener("keydown", onKey);
    };
  }, [open]);

  const cells = useMemo(
    () => buildMonthGrid(view.getFullYear(), view.getMonth()),
    [view],
  );
  const today = new Date();

  return (
    <div
      ref={ref}
      className={cx("mmg-field", error && "mmg-field--error", className)}
      style={{ position: "relative" }}
    >
      {label && (
        <label
          className={cx("mmg-field__label", required && "mmg-field__label--required")}
          htmlFor={id}
        >
          {label}
        </label>
      )}
      <div className="mmg-input-wrap mmg-input-wrap--with-suffix">
        <input
          id={id}
          className="mmg-input"
          readOnly
          required={required}
          disabled={disabled}
          value={fmt(value ?? null)}
          placeholder={placeholder}
          onClick={() => !disabled && setOpen((v) => !v)}
          onFocus={() => !disabled && setOpen(true)}
          aria-haspopup="dialog"
          aria-expanded={open}
        />
        <span className="mmg-input-wrap__icon mmg-input-wrap__icon--suffix">
          <Icon name="calendar-line" />
        </span>
      </div>
      {error ? (
        <span className="mmg-field__error">{error}</span>
      ) : hint ? (
        <span className="mmg-field__hint">{hint}</span>
      ) : null}

      {open && (
        <div
          className="mmg-datepicker"
          style={{ top: "calc(100% + 4px)", left: 0 }}
          role="dialog"
          aria-label="Sélectionner une date"
        >
          <div className="mmg-datepicker__header">
            <button
              type="button"
              className="mmg-datepicker__nav"
              aria-label="Mois précédent"
              onClick={() => setView(new Date(view.getFullYear(), view.getMonth() - 1, 1))}
            >
              <Icon name="arrow-left-line" />
            </button>
            <span className="mmg-datepicker__title">
              {MONTHS[view.getMonth()]} {view.getFullYear()}
            </span>
            <button
              type="button"
              className="mmg-datepicker__nav"
              aria-label="Mois suivant"
              onClick={() => setView(new Date(view.getFullYear(), view.getMonth() + 1, 1))}
            >
              <Icon name="arrow-right-line" />
            </button>
          </div>

          <div className="mmg-datepicker__weekdays">
            {WEEKDAYS.map((w) => (
              <div key={w} className="mmg-datepicker__weekday">{w}</div>
            ))}
          </div>

          <div className="mmg-datepicker__grid">
            {cells.map(({ date, outside }, i) => {
              const selected = value && sameDay(date, value);
              const todayMatch = sameDay(date, today);
              const dis = isDisabled?.(date) ?? false;
              return (
                <button
                  key={i}
                  type="button"
                  className={cx(
                    "mmg-datepicker__day",
                    outside && "mmg-datepicker__day--outside",
                    todayMatch && "mmg-datepicker__day--today",
                  )}
                  aria-selected={selected || undefined}
                  aria-current={todayMatch ? "date" : undefined}
                  disabled={dis}
                  onClick={() => {
                    onChange?.(date);
                    setOpen(false);
                  }}
                >
                  {date.getDate()}
                </button>
              );
            })}
          </div>

          <div className="mmg-datepicker__footer">
            <Button
              size="xs"
              variant="ghost"
              onClick={() => {
                onChange?.(null);
                setOpen(false);
              }}
            >
              Effacer
            </Button>
            <Button
              size="xs"
              variant="tonal"
              onClick={() => {
                onChange?.(today);
                setView(today);
                setOpen(false);
              }}
            >
              Aujourd'hui
            </Button>
          </div>
        </div>
      )}
    </div>
  );
}
