import React, { useState, useRef, useEffect, useCallback, memo } from "react";
import {
  View,
  TextInput,
  StyleSheet,
  BackHandler,
  Platform,
  Keyboard,
} from "react-native";
import PropTypes from "prop-types";

const OTPInput = memo(
  ({
    length = 4,
    onOtpComplete = () => {},
    style,
    inputStyle,
    disabled = false,
    autoFocus = true,
    keyboardType = "numeric",
    placeholder = "",
    secureTextEntry = false,
    error = false,
    errorStyle,
  }) => {
    const [otp, setOtp] = useState(Array(length).fill(""));
    const inputRefs = useRef([]);

    // Report OTP changes to parent component
    useEffect(() => {
      // Always report the current OTP value, even when incomplete
      onOtpComplete(otp.join(""));
    }, [otp, onOtpComplete]);

    const handleChange = useCallback(
      (text, index) => {
        if (disabled) return;

        // Handle paste event (multiple characters)
        if (text.length > 1) {
          const pastedData = text.slice(0, length);
          const newOtp = Array(length).fill("");

          for (let i = 0; i < pastedData.length; i++) {
            if (!isNaN(pastedData[i]) && pastedData[i] !== "") {
              newOtp[i] = pastedData[i];
            }
          }

          setOtp(newOtp);

          const focusIndex = Math.min(pastedData.length, length - 1);
          setTimeout(() => {
            inputRefs.current[focusIndex]?.focus();
          }, 0);

          if (newOtp.every((val) => val !== "")) {
            Keyboard.dismiss();
          }

          return;
        }

        // Handle single character input
        const newOtp = [...otp];

        // Only accept numeric input
        if (!isNaN(text) && text !== "") {
          newOtp[index] = text;
          setOtp(newOtp);

          // Move to next input if available
          if (index < length - 1) {
            inputRefs.current[index + 1]?.focus();
          } else {
            // Last digit entered, can dismiss keyboard
            Keyboard.dismiss();
          }
        } else if (text === "") {
          // Handle empty input (usually from clear)
          newOtp[index] = "";
          setOtp(newOtp);
        }
      },
      [disabled, length, otp]
    );

    // Handle key press events (for backspace navigation)
    const handleKeyPress = useCallback(
      (event, index) => {
        const { key } = event.nativeEvent;

        if (key === "Backspace") {
          // If current input has value, clear it
          if (otp[index] !== "") {
            const newOtp = [...otp];
            newOtp[index] = "";
            setOtp(newOtp);
          }
          // If current input is empty and not the first input, move focus to previous
          else if (index > 0) {
            inputRefs.current[index - 1]?.focus();
          }
        }
      },
      [otp]
    );

    // Handle hardware back button on Android
    const handleBackPress = useCallback(() => {
      const focusedInputIndex = inputRefs.current.findIndex(
        (ref) => ref && ref.isFocused()
      );

      // No input has focus, find last filled input
      if (focusedInputIndex === -1) {
        const lastFilledIndex = [...otp]
          .reverse()
          .findIndex((val) => val !== "");
        if (lastFilledIndex !== -1) {
          const index = length - 1 - lastFilledIndex;
          inputRefs.current[index]?.focus();
          return true;
        }
        return false;
      }

      // Current field has value, clear it
      if (otp[focusedInputIndex] !== "") {
        const newOtp = [...otp];
        newOtp[focusedInputIndex] = "";
        setOtp(newOtp);
        return true;
      }

      // Current field is empty, move focus to previous if possible
      if (focusedInputIndex > 0) {
        inputRefs.current[focusedInputIndex - 1]?.focus();
        return true;
      }

      // Let the system handle the back button (navigation)
      return false;
    }, [otp, length]);

    // Set up event listeners
    useEffect(() => {
      let backHandler;
      let keyDownHandler;

      if (Platform.OS === "android") {
        backHandler = BackHandler.addEventListener(
          "hardwareBackPress",
          handleBackPress
        );
      } else {
        // Handle backspace on web/iOS
        keyDownHandler = (event) => {
          if (event.key === "Backspace") {
            const focusedInputIndex = inputRefs.current.findIndex(
              (ref) => ref && ref.isFocused()
            );

            if (focusedInputIndex === -1) return;

            // Current field has value, clear it
            if (otp[focusedInputIndex] !== "") {
              const newOtp = [...otp];
              newOtp[focusedInputIndex] = "";
              setOtp(newOtp);
              event.preventDefault();
              return;
            }

            // Current field is empty, move to previous
            if (focusedInputIndex > 0) {
              inputRefs.current[focusedInputIndex - 1]?.focus();
              event.preventDefault();
            }
          }
        };

        if (typeof window !== "undefined") {
          window.addEventListener("keydown", keyDownHandler);
        }
      }

      return () => {
        if (Platform.OS === "android") {
          backHandler?.remove();
        } else if (typeof window !== "undefined") {
          window.removeEventListener("keydown", keyDownHandler);
        }
      };
    }, [handleBackPress, otp]);

    // Reset the OTP input
    const reset = useCallback(() => {
      setOtp(Array(length).fill(""));
      setTimeout(() => {
        inputRefs.current[0]?.focus();
      }, 0);
    }, [length]);

    // Handle disabled state
    useEffect(() => {
      if (disabled) {
        reset();
      }
    }, [disabled, reset]);

    return (
      <View
        style={[styles.otpContainer, style]}
        accessible={true}
        accessibilityLabel={`OTP input with ${length} digits`}
        accessibilityHint="Enter your OTP code"
      >
        {Array(length)
          .fill(0)
          .map((_, index) => (
            <TextInput
              key={index}
              ref={(ref) => (inputRefs.current[index] = ref)}
              style={[
                styles.otpInput,
                error && styles.errorInput,
                inputStyle,
                errorStyle,
              ]}
              value={otp[index]}
              onChangeText={(text) => handleChange(text, index)}
              onKeyPress={(event) => handleKeyPress(event, index)}
              keyboardType={keyboardType}
              maxLength={1}
              textAlign="center"
              autoFocus={autoFocus && index === 0}
              editable={!disabled}
              placeholder={placeholder}
              secureTextEntry={secureTextEntry}
              selectTextOnFocus
              contextMenuHidden={Platform.OS === "android"}
            />
          ))}
      </View>
    );
  }
);

OTPInput.propTypes = {
  length: PropTypes.number,
  onOtpComplete: PropTypes.func,
  style: PropTypes.object,
  inputStyle: PropTypes.object,
  disabled: PropTypes.bool,
  autoFocus: PropTypes.bool,
  keyboardType: PropTypes.string,
  placeholder: PropTypes.string,
  secureTextEntry: PropTypes.bool,
  error: PropTypes.bool,
  errorStyle: PropTypes.object,
};

const styles = StyleSheet.create({
  otpContainer: {
    flexDirection: "row",
    justifyContent: "space-between",
  },
  otpInput: {
    width: 50,
    height: 50,
    borderWidth: 1,
    borderColor: "#ddd",
    borderRadius: 5,
    marginHorizontal: 5,
    fontSize: 18,
    textAlign: "center",
    backgroundColor: "#fff",
  },
  errorInput: {
    borderColor: "#ff0000",
  },
});

export default OTPInput;
