/* eslint-disable @typescript-eslint/no-explicit-any */
import { Box, styled, useTheme } from "@mui/material";
import React from "react";

const InputElement = styled("input")<
  React.InputHTMLAttributes<HTMLInputElement>
>(() => ({
  "& input[type=number]": {
    MozAppearance: "textfield",
  },
  "& input[type=number]::-webkit-outer-spin-button, & input[type=number]::-webkit-inner-spin-button":
    {
      WebkitAppearance: "none",
      margin: 0,
    },
}));

const OTPInput = function (props: any) {
  const {
    onChange,
    separator = "-",
    length = 4,
    type = "number",
    style,
    boxWidth,
    boxHeight,
  } = props;
  const theme = useTheme();
  const [otp, setOtp] = React.useState("");

  const inputRefs = React.useRef<HTMLInputElement[]>(
    new Array(length).fill(null)
  );

  const focusInput = (targetIndex: number) => {
    const targetInput = inputRefs.current[targetIndex];
    targetInput.focus();
  };

  const selectInput = (targetIndex: number) => {
    const targetInput = inputRefs.current[targetIndex];
    targetInput.select();
  };

  const handleKeyDown = (
    event: React.KeyboardEvent<HTMLInputElement>,
    currentIndex: number
  ) => {
    switch (event.key) {
      case "ArrowUp":
      case "ArrowDown":
      case " ":
        event.preventDefault();
        break;
      case "ArrowLeft":
        event.preventDefault();
        if (currentIndex > 0) {
          focusInput(currentIndex - 1);
          selectInput(currentIndex - 1);
        }
        break;
      case "ArrowRight":
        event.preventDefault();
        if (currentIndex < length - 1) {
          focusInput(currentIndex + 1);
          selectInput(currentIndex + 1);
        }
        break;
      case "Delete":
        event.preventDefault();
        setOtp((prevOtp) => {
          const otp =
            prevOtp.slice(0, currentIndex) + prevOtp.slice(currentIndex + 1);
          onChange(otp);
          return otp;
        });

        break;
      case "Backspace":
        event.preventDefault();
        if (currentIndex > 0) {
          focusInput(currentIndex - 1);
          selectInput(currentIndex - 1);
        }

        setOtp((prevOtp) => {
          const otp =
            prevOtp.slice(0, currentIndex) + prevOtp.slice(currentIndex + 1);
          onChange(otp);
          return otp;
        });
        break;

      default:
        break;
    }
  };

  const handleOtpChange = (
    event: React.ChangeEvent<HTMLInputElement>,
    currentIndex: number
  ) => {
    const currentValue = event.target.value;

    if (type === "number" && !/^\d$/.test(currentValue)) {
      return;
    }

    if (type === "alphabet" && !/^[a-zA-Z]+$/.test(currentValue)) {
      return;
    }

    let indexToEnter = 0;

    while (indexToEnter <= currentIndex) {
      if (
        inputRefs.current[indexToEnter].value &&
        indexToEnter < currentIndex
      ) {
        indexToEnter += 1;
      } else {
        break;
      }
    }
    setOtp((prev) => {
      const otpArray = prev.split("");
      const lastValue = currentValue[currentValue.length - 1];
      otpArray[indexToEnter] = lastValue;
      onChange(otpArray.join(""));
      return otpArray.join("");
    });
    if (currentValue !== "") {
      if (indexToEnter < length - 1) {
        focusInput(indexToEnter + 1);
      }
    }
  };

  const handleClick = (
    event: React.MouseEvent<HTMLInputElement, MouseEvent>,
    currentIndex: number
  ) => {
    selectInput(currentIndex);
  };

  const handlePaste = (
    event: React.ClipboardEvent<HTMLInputElement>,
    currentIndex: number
  ) => {
    event.preventDefault();
    const clipboardData = event.clipboardData;

    if (clipboardData.types.includes("text/plain")) {
      let pastedText = clipboardData.getData("text/plain");
      pastedText = pastedText.substring(0, length).trim();
      let indexToEnter = 0;

      while (indexToEnter <= currentIndex) {
        if (
          inputRefs.current[indexToEnter].value &&
          indexToEnter < currentIndex
        ) {
          indexToEnter += 1;
        } else {
          break;
        }
      }

      const otpArray = otp.split("");

      for (let i = indexToEnter; i < length; i += 1) {
        const lastValue = pastedText[i - indexToEnter] ?? " ";
        otpArray[i] = lastValue;
      }
      onChange(otpArray.join(""));

      setOtp(otpArray.join(""));
    }
  };

  return (
    <Box
      sx={{
        display: "flex",
        alignItems: "center",
        gap: 1,
        width: "100%",
      }}
      css={style}
    >
      {new Array(length).fill(null).map((_, index) => (
        <React.Fragment key={index}>
          <InputElement
            ref={(ele) => {
              inputRefs.current[index] = ele!;
            }}
            type={type === "number" && "tel"}
            css={style}
            sx={{
              maxWidth: `${boxWidth || 40}px`,
              height: `${boxHeight || 32}px`,
              textAlign: "center",
              color:theme.palette.text.primary,
              background: theme.palette.background.default,
              borderRadius: "2px",
              // boxShadow: `2px 2px 2px 2px 4spx ${theme.palette.action.selected}`,
              border: `1px solid ${theme.palette.action.focus}`,
              "& input[type=number]": {
                MozAppearance: "textfield"
              },
              "& input[type=number]::-webkit-outer-spin-button, & input[type=number]::-webkit-inner-spin-button":
                {
                  WebkitAppearance: "none",
                  margin: 0,
                },
            }}
            onKeyDown={(event) => handleKeyDown(event, index)}
            onChange={(event) => handleOtpChange(event, index)}
            onClick={(event) => handleClick(event, index)}
            onPaste={(event) => handlePaste(event, index)}
            value={otp[index] ?? ""}
            aria-label={`Digit ${index + 1} of OTP`}
          />
          {index === length - 1 ? null : separator}
        </React.Fragment>
      ))}
    </Box>
  );
};

export default OTPInput;
