import { useEffect, useMemo, useState } from "react";

import { parseDisplayDate } from "@/lib/booking-search";

type Props = {
  id?: string;
  invalid?: boolean;
  /** Latest allowed birth date (dd-mm-yyyy), usually ngày đi tàu. */
  maxDate: string;
  value: string;
  onChange: (displayDate: string) => void;
};

type DateParts = {
  day: number;
  month: number;
  year: number;
};

const EMPTY_PARTS: DateParts = { day: 0, month: 0, year: 0 };

function pad2(n: number): string {
  return String(n).padStart(2, "0");
}

function toStorage({ day, month, year }: DateParts): string {
  return `${pad2(day)}-${pad2(month)}-${year}`;
}

function parseParts(value: string): DateParts | null {
  const parsed = parseDisplayDate(value);
  if (!parsed) return null;
  return {
    day: parsed.getDate(),
    month: parsed.getMonth() + 1,
    year: parsed.getFullYear(),
  };
}

function daysInMonth(month: number, year: number): number {
  return new Date(year, month, 0).getDate();
}

function clampParts(parts: DateParts, max: Date): DateParts {
  let { day, month, year } = parts;

  if (year && month && day) {
    day = Math.min(day, daysInMonth(month, year));
    const candidate = parseDisplayDate(toStorage({ day, month, year }));
    if (candidate && candidate > max) {
      return {
        day: max.getDate(),
        month: max.getMonth() + 1,
        year: max.getFullYear(),
      };
    }
  }

  return { day, month, year };
}

function isComplete(parts: DateParts): boolean {
  return parts.day > 0 && parts.month > 0 && parts.year > 0;
}

export function BookingBirthDateControl({ id, invalid = false, maxDate, value, onChange }: Props) {
  const max = useMemo(() => parseDisplayDate(maxDate) ?? new Date(), [maxDate]);
  const maxYear = max.getFullYear();

  const [parts, setParts] = useState<DateParts>(() => parseParts(value) ?? EMPTY_PARTS);

  useEffect(() => {
    if (!value.trim()) {
      setParts(EMPTY_PARTS);
      return;
    }
    const parsed = parseParts(value);
    if (parsed) {
      setParts(parsed);
    }
  }, [value]);

  const years = useMemo(() => {
    const minYear = Math.max(1920, maxYear - 100);
    return Array.from({ length: maxYear - minYear + 1 }, (_, index) => maxYear - index);
  }, [maxYear]);

  const months = useMemo(() => Array.from({ length: 12 }, (_, index) => index + 1), []);

  const days = useMemo(() => {
    if (!parts.year || !parts.month) {
      return Array.from({ length: 31 }, (_, index) => index + 1);
    }
    const count = daysInMonth(parts.month, parts.year);
    return Array.from({ length: count }, (_, index) => index + 1);
  }, [parts.month, parts.year]);

  function update(next: Partial<DateParts>) {
    const merged = clampParts({ ...parts, ...next }, max);
    setParts(merged);
    if (isComplete(merged)) {
      onChange(toStorage(merged));
    }
  }

  return (
    <div className={`ferry-booking__birth-date${invalid ? " is-invalid" : ""}`} id={id}>
      <select
        aria-label="Ngày sinh"
        className="ferry-booking__birth-date-part"
        value={parts.day || ""}
        onChange={(e) => update({ day: Number(e.target.value) })}
      >
        <option value="">Ngày</option>
        {days.map((day) => (
          <option key={day} value={day}>
            {pad2(day)}
          </option>
        ))}
      </select>
      <select
        aria-label="Tháng sinh"
        className="ferry-booking__birth-date-part"
        value={parts.month || ""}
        onChange={(e) => update({ month: Number(e.target.value) })}
      >
        <option value="">Tháng</option>
        {months.map((month) => (
          <option key={month} value={month}>
            {pad2(month)}
          </option>
        ))}
      </select>
      <select
        aria-label="Năm sinh"
        className="ferry-booking__birth-date-part ferry-booking__birth-date-part--year"
        value={parts.year || ""}
        onChange={(e) => update({ year: Number(e.target.value) })}
      >
        <option value="">Năm</option>
        {years.map((year) => (
          <option key={year} value={year}>
            {year}
          </option>
        ))}
      </select>
    </div>
  );
}
