import { forwardRef } from "react";
import DatePicker, { registerLocale } from "react-datepicker";
import { cs } from "date-fns/locale";
import { parse, format } from "date-fns";
import "react-datepicker/dist/react-datepicker.css";

registerLocale("cs", cs);

// Ensure portal root exists
if (
  typeof document !== "undefined" &&
  !document.getElementById("datepicker-portal")
) {
  const el = document.createElement("div");
  el.id = "datepicker-portal";
  document.body.appendChild(el);
}

const isTouchDevice = () =>
  typeof window !== "undefined" &&
  ("ontouchstart" in window || navigator.maxTouchPoints > 0);

interface CustomInputProps {
  value?: string;
  onClick?: () => void;
  onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
  placeholder?: string;
  required?: boolean;
  readOnly?: boolean;
  disabled?: boolean;
}

const CustomInput = forwardRef<HTMLInputElement, CustomInputProps>(
  (
    { value, onClick, onChange, placeholder, required, readOnly, disabled },
    ref,
  ) => (
    <input
      className="admin-form-input"
      onClick={onClick}
      onChange={onChange}
      value={value}
      placeholder={placeholder}
      ref={ref}
      required={required}
      readOnly={readOnly}
      disabled={disabled}
      autoComplete="off"
    />
  ),
);

interface NativeInputProps {
  mode: string;
  value: string;
  onChange: (value: string) => void;
  required?: boolean;
  minDate?: string;
  maxDate?: string;
  disabled?: boolean;
  placeholder?: string;
}

const modeToInputType: Record<string, string> = {
  month: "month",
  time: "time",
};

function NativeInput({
  mode,
  value,
  onChange,
  required,
  minDate,
  maxDate,
  disabled,
  placeholder,
}: NativeInputProps) {
  const type = modeToInputType[mode] || "date";
  // For time inputs, min/max must be in HH:mm format, not date format
  const formatTimeMinMax = (val: string | undefined): string | undefined => {
    if (!val) return undefined;
    // If it looks like a date string (yyyy-MM-dd), extract time portion if present,
    // otherwise it's not a valid time min/max — return undefined
    if (val.includes("T")) return val.split("T")[1]?.substring(0, 5);
    if (val.includes(":")) return val.substring(0, 5);
    return undefined;
  };
  const minProp =
    mode === "time" ? formatTimeMinMax(minDate) : minDate || undefined;
  const maxProp =
    mode === "time" ? formatTimeMinMax(maxDate) : maxDate || undefined;
  return (
    <input
      type={type}
      lang="cs"
      value={value || ""}
      onChange={(e) => onChange(e.target.value)}
      className="admin-form-input"
      placeholder={placeholder}
      required={required}
      disabled={disabled}
      min={minProp}
      max={maxProp}
    />
  );
}

interface AdminDatePickerProps {
  mode?: "date" | "month" | "time";
  value: string;
  onChange: (value: string) => void;
  minDate?: string;
  maxDate?: string;
  disabled?: boolean;
  placeholder?: string;
  required?: boolean;
}

export default function AdminDatePicker({
  mode = "date",
  value,
  onChange,
  required,
  minDate,
  maxDate,
  disabled,
  placeholder,
}: AdminDatePickerProps) {
  const useNative = isTouchDevice();

  // Mode-aware default placeholder so empty date fields always show a format
  // hint (callers can still override, e.g. "Od"/"Do" on range filters).
  const effectivePlaceholder =
    placeholder ??
    (mode === "time" ? "hh:mm" : mode === "month" ? "mm.rrrr" : "dd.mm.rrrr");

  if (useNative) {
    return (
      <NativeInput
        mode={mode}
        value={value}
        onChange={onChange}
        required={required}
        minDate={minDate}
        maxDate={maxDate}
        disabled={disabled}
        placeholder={effectivePlaceholder}
      />
    );
  }

  const toDate = (val: string | null | undefined): Date | null => {
    if (!val) return null;
    try {
      if (mode === "date") return parse(val, "yyyy-MM-dd", new Date());
      if (mode === "time") {
        const [h, m] = val.split(":");
        const d = new Date();
        d.setHours(parseInt(h, 10), parseInt(m, 10), 0, 0);
        return d;
      }
      if (mode === "month") return parse(val, "yyyy-MM", new Date());
    } catch {
      return null;
    }
    return null;
  };

  const handleChange = (date: Date | null) => {
    if (!date) {
      onChange("");
      return;
    }
    if (mode === "date") onChange(format(date, "yyyy-MM-dd"));
    else if (mode === "time") onChange(format(date, "HH:mm"));
    else if (mode === "month") onChange(format(date, "yyyy-MM"));
  };

  const parseMinMax = (val: string | undefined): Date | undefined => {
    if (!val) return undefined;
    try {
      if (mode === "date") return parse(val, "yyyy-MM-dd", new Date());
      if (mode === "month") return parse(val, "yyyy-MM", new Date());
    } catch {
      return undefined;
    }
    return undefined;
  };

  const customInput = (
    <CustomInput
      required={required}
      placeholder={effectivePlaceholder}
      disabled={disabled}
    />
  );

  const commonProps = {
    selected: toDate(value),
    onChange: handleChange,
    locale: "cs",
    customInput,
    placeholderText: effectivePlaceholder,
    minDate: parseMinMax(minDate),
    maxDate: parseMinMax(maxDate),
    popperPlacement: "bottom-start" as const,
    portalId: "datepicker-portal",
    disabled,
  };

  if (mode === "time") {
    return (
      <DatePicker
        {...commonProps}
        showTimeSelect
        showTimeSelectOnly
        timeIntervals={5}
        timeCaption="Čas"
        dateFormat="HH:mm"
        timeFormat="HH:mm"
      />
    );
  }

  if (mode === "month") {
    return (
      <DatePicker {...commonProps} showMonthYearPicker dateFormat="MM/yyyy" />
    );
  }

  return <DatePicker {...commonProps} dateFormat="dd.MM.yyyy" />;
}
