import React, { useCallback, useState } from "react";

import { FormHelperText, Stack } from "@mui/material";
import Grid from "@mui/material/Grid2";
import { DatePicker, DatePickerProps, LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterLuxon } from "@mui/x-date-pickers/AdapterLuxon";

import { DateTime } from "luxon";

import { useCardContext } from "../../contexts/CardContext";
import LabeledValue from "../LabeledValue";

import { CardFieldBaseProps } from "./shared";

export interface CardFieldDateProps
  extends Omit<DatePickerProps<DateTime>, "label" | "value">,
    CardFieldBaseProps,
    React.PropsWithChildren {
  dateFormatter?: (date: DateTime) => string;
  type: "date";
  label: string;
  formName: string;
  value?: DateTime | Date | string | null | undefined;
  isReadable?: boolean;
  isEditable?: boolean;

  /** E.g en-GB for "Monday, tuesday, ..., sunday" instead of "Sunday, monday ..., saturday" */
  adapterLocale?: string;
}

export const CardFieldDate: React.FC<Omit<CardFieldDateProps, "type">> = ({
  dateFormatter = (date) => (date.isValid ? date.toISODate() : ""),
  fallback = "—",
  fallbackPredicate = (date: DateTime | undefined) => !date?.isValid,
  formName,
  helperText,
  isDisabled = false,
  isEditable = true,
  isReadable = true,
  label,
  size = "grow",
  sx,
  adapterLocale,
  value: defaultValue,
  ...props
}) => {
  const { isCompact, isEditing } = useCardContext();

  const [value, setValue] = useState<DateTime | undefined>(() => {
    if (defaultValue instanceof Date) {
      return DateTime.fromJSDate(defaultValue);
    } else if (defaultValue instanceof DateTime) {
      return defaultValue;
    } else if (typeof defaultValue === "string") {
      try {
        const date = DateTime.fromISO(defaultValue);
        if (date.isValid) {
          return date;
        } else {
          console.error(`[CARD_FIELD_DATE] Invalid date string: ${defaultValue}`);
          return undefined;
        }
      } catch (error) {
        console.error(`[CARD_FIELD_DATE] ${error}`);
        return undefined;
      }
    } else {
      return undefined;
    }
  });

  const handleDateChange = useCallback(
    (date: DateTime | null) => {
      if (date != null) setValue(date);
    },
    [setValue],
  );

  return (
    <Grid size={size}>
      {isEditing && isEditable ? (
        <Stack direction="column" py={1}>
          <LocalizationProvider adapterLocale={adapterLocale} dateAdapter={AdapterLuxon}>
            <DatePicker
              defaultValue={value}
              disabled={isDisabled}
              label={label}
              name={formName}
              sx={{ width: "100%", ...sx }}
              onChange={handleDateChange}
              {...props}
            />
          </LocalizationProvider>

          {helperText != null && <FormHelperText sx={{ mb: 1 }}>{helperText}</FormHelperText>}
        </Stack>
      ) : (
        isReadable && (
          <LabeledValue
            compact={isCompact}
            label={label}
            value={fallbackPredicate(value) ? fallback : dateFormatter(value!)}
          />
        )
      )}
    </Grid>
  );
};

export default CardFieldDate;
