import { useContext } from 'react';
import { Box, styled } from '@mui/material';
import { DataContext } from '../context/Context';
import ComponentWrapper from '../common/ComponentWrapper';
import { getFieldName } from '../permissions/getFieldName';
import { InputElemntProps, inputProps } from '../interface/inputfieldProps';
import { useDebouncedChange } from '@jsonforms/material-renderers';
import { getComponentProps } from '../common/getComponentProps';
import React from 'react';
import { useJsonForms } from '@jsonforms/react';

const InputElement = styled('input')<InputElemntProps>(
 ({ theme, otpBoxStyle }) => ({
  ...theme?.OTPInputBoxStyle,
  ...otpBoxStyle,
 }),
);

const OTPInput = function (props: inputProps) {
 const { data, uischema, path, schema, handleChange, rootSchema } = props;
 const { pageName, permissions, theme ,serviceProvider} = useContext(DataContext);
 const uischemaData = uischema?.config?.main;
 const fieldName = getFieldName(path);
 const separator = uischemaData?.seperator || '';
 const length = uischemaData?.length || 4;

 const [otp, setOtp] = React.useState('');
 const eventToValue = (ev: any) => (ev === '' ? undefined : ev);
 const ctx = useJsonForms();
 const dynamicStyle = React.useMemo(() => {
  return serviceProvider(
   ctx,
   {
    onClick: uischema.config?.main?.styleFunction || 'getStyle',
   },
   {
    event: { _reactName: 'onClick' },
    path,
   },
  );
 }, [data, path]);
 const componentStyle = { ...uischema.config?.style, ...dynamicStyle };
 const [input, onChange] = useDebouncedChange(
  handleChange,
  '',
  data,
  path,
  eventToValue,
 ) as [string, any, () => void];

 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 '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':
   case 'Backspace':
    event.preventDefault();

    setOtp((prevOtp) => {
     const otpArray = prevOtp.split('');
     otpArray[currentIndex] = '';
     const newOtp = otpArray.join('');
     onChange(newOtp);
     return newOtp;
    });

    if (event.key === 'Backspace' && currentIndex > 0) {
     focusInput(currentIndex - 1);
    }

    break;

   default:
    break;
  }
 };

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

  if (uischemaData?.type === 'number' && !/^\d$/.test(currentValue)) return;

  if (uischemaData?.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;

   const newOtp = otpArray.join('');

   onChange(newOtp);

   return newOtp;
  });

  if (currentValue !== '' && indexToEnter < length - 1) {
   focusInput(indexToEnter + 1);
  }
 };

 const handleClick = (
  event: React.MouseEvent<HTMLInputElement>,
  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++) {
    const lastValue = pastedText[i - indexToEnter] ?? '';
    otpArray[i] = lastValue;
   }

   const newOtp = otpArray.join('');

   setOtp(newOtp);
   onChange(newOtp);
  }
 };

 return (
  <ComponentWrapper
   {...getComponentProps(
    `${pageName}:${fieldName}`,
    permissions,
    schema,
    rootSchema,
   )}
  >
   <Box sx={componentStyle.OTP_ContainerStyle}>
    {new Array(length).fill(null).map((_, index) => (
     <React.Fragment key={index}>
      <InputElement
       ref={(ele) => {
        inputRefs.current[index] = ele!;
       }}
       theme={theme}
       onKeyDown={(event) => handleKeyDown(event, index)}
       onChange={(event) => handleOtpChange(event, index)}
       onClick={(event) => handleClick(event, index)}
       onPaste={(event) => handlePaste(event, index)}
       value={
        uischemaData?.masking ? (otp[index] ? '•' : '') : (otp[index] ?? '')
       }
       aria-label={`Digit ${index + 1} of OTP`}
       otpBoxStyle={componentStyle}
      />
      {index === length - 1 ? null : separator}
     </React.Fragment>
    ))}
   </Box>
  </ComponentWrapper>
 );
};

export default OTPInput;
