import React, {
  ChangeEventHandler,
  useCallback,
  useEffect,
  useRef,
  useState,
} from "react";
import { Box, Input, SxProps, TableCell } from "@mui/material";

interface Props<T> {
  value: T;
  onChange: (newValue?: T) => void;
  renderValue?: (value: T) => string;
  convertValue: (inputValue?: string) => T;
  cellSx?: SxProps;
  inputSx?: SxProps;
}

const TableCellEdit = <T,>({
  value,
  renderValue = (val) => `${val}`,
  convertValue,
  onChange,
  cellSx,
  inputSx,
}: Props<T>) => {
  const [editMode, setEditMode] = useState(false);
  const [input, setInput] = useState<string>();
  const inputRef = useRef<HTMLInputElement>(null);

  const onClick = useCallback(() => {
    setEditMode(true);
    setInput(`${value}`);
  }, [value]);

  const onInputChange = useCallback<ChangeEventHandler<HTMLInputElement>>(
    (e) => setInput(e.target.value),
    [],
  );

  const onBlur = useCallback(() => {
    setEditMode(false);
    onChange(convertValue(input));
    setInput(undefined);
  }, [convertValue, input, onChange]);

  useEffect(() => {
    if (editMode && inputRef.current) {
      inputRef.current?.focus();
    }
  }, [editMode]);

  return (
    <TableCell
      sx={{
        outline: editMode ? "1px solid" : undefined,
        outlineColor: editMode ? "primary.main" : undefined,
        ...cellSx,
      }}
    >
      <Input
        sx={{
          display: editMode ? "block" : "none",
          "::after": { display: "none " },
          "::before": { display: "none " },
          height: "inherit",
          width: "inherit",
          padding: 0,
          fontWeight: "inherit",
          lineHeight: "inherit",
          ...inputSx,
        }}
        inputRef={inputRef}
        value={input}
        onChange={onInputChange}
        onBlur={onBlur}
        type={typeof value === "number" ? "number" : "text"}
      />
      <Box sx={{ display: editMode ? "none" : "block" }} onClick={onClick}>
        {renderValue(value)}
      </Box>
    </TableCell>
  );
};

export default TableCellEdit;
