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

import { FormHelperText, Stack } from "@mui/material";
import FormControl from "@mui/material/FormControl";
import Grid from "@mui/material/Grid2";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import Select, { SelectChangeEvent, type SelectProps } from "@mui/material/Select";

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

import { CardFieldBaseProps, FormOption } from "./shared";

export interface CardFieldSelectProps
  extends React.PropsWithChildren,
    Omit<SelectProps, "size" | "value" | "label">,
    CardFieldBaseProps {
  type: "select";
  /** A custom fallback empty state when you want to emulate a non-nullish default state. */
  emptyValue?: FormOption;
  value: FormOption | undefined;
  isEditable?: boolean;
  onUpdated?: (val: string) => void;
}

export const CardFieldSelect: React.FC<Omit<CardFieldSelectProps, "type">> = ({
  emptyValue,
  fallback = "—",
  fallbackPredicate = (value: unknown) => value != null && value !== "",
  formName,
  helperText,
  isDisabled = false,
  isEditable = true,
  isReadable = true,
  label,
  options,
  required = false,
  size = "grow",
  value: defaultValue = undefined,
  onUpdated,
  ...props
}) => {
  const { isCompact, isEditing } = useCardContext();
  const [value, setValue] = useState(defaultValue?.label ?? emptyValue?.label ?? "");

  const handleChange = useCallback(
    (event: SelectChangeEvent<unknown>) => {
      const currentValue = event.target.value as string;
      setValue(currentValue);
      if (onUpdated) onUpdated(currentValue);
    },
    [setValue, onUpdated],
  );

  return (
    <Grid size={size}>
      {isEditing && isEditable ? (
        <Stack direction="column">
          <FormControl fullWidth>
            <InputLabel>{label}</InputLabel>
            <Select
              disabled={isDisabled}
              label={label}
              name={formName}
              required={required}
              value={value}
              onChange={handleChange}
              {...props}
            >
              {options?.map((opt) => (
                <MenuItem key={opt.id} value={opt.label}>
                  {opt.label}
                </MenuItem>
              ))}
            </Select>
          </FormControl>

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

export default CardFieldSelect;
