import React, { forwardRef, useState, useEffect, useRef } from "react";
import { getSizeStyles } from "../../data/getInputSizes";
import { bgInputPrimaryColor, textColor } from "../../data/getColorBasedOnMode";
import { motion, AnimatePresence } from "framer-motion";
import { checkIsMobile } from "../../utils/checkIsMobile";

interface TextfieldProps
  extends Omit<
    React.InputHTMLAttributes<HTMLInputElement>,
    "type" | "value" | "defaultValue"
  > {
  label?: string;
  value?: string | number;
  error?: boolean;
  password?: boolean;
  fullWidth?: boolean;
  isAutoComplete?: boolean;
  helperText?: string;
  className?: string;
  inputSize?: "small" | "medium" | "large";
  children?: React.ReactNode;
  isNumber?: boolean;
  handleCloseInput?: () => void;
  start?: React.ReactNode;
  end?: React.ReactNode;
  formattedNumber?: boolean;
}

const Textfield = forwardRef<HTMLInputElement, TextfieldProps>(
  (
    {
      placeholder,
      error,
      value = "",
      helperText,
      password,
      className,
      inputSize = "medium",
      fullWidth,
      children,
      isNumber = false,
      isAutoComplete = false,
      onChange,
      handleCloseInput,
      start,
      end,
      formattedNumber = false,
      onClick: propsOnClick,
      onFocus: propsOnFocus,
      onBlur: propsOnBlur,
      ...props
    },
    ref
  ) => {
    const [inputValue, setInputValue] = useState(value);
    const [displayValue, setDisplayValue] = useState(value);
    const inputRef = useRef<HTMLInputElement>(null);
    const isFirstClickRef = useRef(true);
    const isMobile = checkIsMobile();

    useEffect(() => {
      setInputValue(value);
      if (formattedNumber) {
        if (value === "" || value === null || value === undefined) {
          setDisplayValue("");
        } else {
          const numValue =
            typeof value === "string" ? value.replace(/,/g, "") : value;
          setDisplayValue(Number(numValue).toLocaleString());
        }
      } else {
        setDisplayValue(value);
      }
    }, [value, placeholder, formattedNumber]);

    const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
      let value = e.target.value;

      if (formattedNumber) {
        value = value.replace(/[^0-9]/g, "");

        if (value === "") {
          setDisplayValue("");
        } else {
          const formatted = Number(value).toLocaleString();
          setDisplayValue(formatted);
        }

        e.target.value = value;
      } else {
        setDisplayValue(value);
      }

      setInputValue(value);

      if (onChange) {
        onChange(e);
      }
    };

    const handleMouseDown = () => {
      if (isAutoComplete && isMobile && isFirstClickRef.current) {
        if (inputRef.current) {
          inputRef.current.readOnly = true;
        }
      }
    };

    const handleTouchStart = () => {
      if (isAutoComplete && isMobile && isFirstClickRef.current) {
        if (inputRef.current) {
          inputRef.current.readOnly = true;
        }
      }
    };

    const handleClick = (e: React.MouseEvent<HTMLInputElement>) => {
      if (isAutoComplete && isMobile && isFirstClickRef.current) {
        e.preventDefault();
        if (inputRef.current) {
          inputRef.current.blur();
          setTimeout(() => {
            if (inputRef.current) {
              inputRef.current.readOnly = false;
            }
          }, 100);
        }
        isFirstClickRef.current = false;
        return;
      }
      if (propsOnClick) {
        propsOnClick(e);
      }
    };

    const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => {
      if (isAutoComplete && isMobile && isFirstClickRef.current) {
        if (inputRef.current) {
          inputRef.current.blur();
          setTimeout(() => {
            if (inputRef.current) {
              inputRef.current.readOnly = false;
            }
          }, 100);
        }
        isFirstClickRef.current = false;
        return;
      }
      if (propsOnFocus) {
        propsOnFocus(e);
      }
    };

    const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
      isFirstClickRef.current = true;
      if (propsOnBlur) {
        propsOnBlur(e);
      }
    };

    const floatingLabelVariants = {
      hidden: {
        opacity: 0,
        y: 10,
        scale: 1,
        transition: {
          duration: 0.15,
          ease: [0.4, 0, 0.2, 1],
        },
      },
      visible: {
        opacity: 1,
        y: 0,
        scale: 0.9,
        transition: {
          duration: 0.2,
          ease: [0.4, 0, 0.2, 1],
          delay: 0.05,
        },
      },
    };

    const shouldTextAlignLeft = isNumber && inputValue !== "";
    const shouldFloatLabel = inputValue || inputValue === 0;

    const inputClass = `py-2 ${
      !start && !end && "border-[0.3px]"
    }  border-gray1-200 rounded-lg outline-0 dark:border-dark-400 
      ${className || ""} ${start && end && "text-center"}  ${
      shouldTextAlignLeft ? "text-left" : ""
    } 
      ${error ? "border-red-400 focus:ring-red-400" : ""}
      placeholder:text-dark-400 dark:placeholder:text-dark-100 ${
        (!start || !end) && bgInputPrimaryColor
      } 
      ${getSizeStyles(inputSize).padding} ${textColor}
      ${
        props.disabled
          ? "opacity-50 cursor-not-allowed bg-gray-100 dark:bg-dark-300 border-gray-300 dark:border-dark-500"
          : "cursor-text"
      }`;

    const floatingLabelClass = `absolute right-1 bg-white dark:bg-dark-200 rounded-lg -top-2 text-[10px] px-2 mt-0.5 dark:text-dark-800 ${
      error ? "text-red-400" : "text-gray-500"
    } ${props.disabled ? "opacity-50" : ""} transition-all duration-200`;

    return (
      <div className={`flex flex-col  gap-1 ${fullWidth ? "w-full" : ""} `}>
        <div
          className={`relative ${fullWidth ? "w-full" : ""} ${
            (start || end) &&
            `border-1 rounded-lg border-gray1-200 dark:bg-dark-500 ${
              start ? "pr-2" : ""
            } ${end ? "pl-2" : ""} w-auto text-right`
          }`}
        >
          <div className="flex items-center justify-between">
            {start && (
              <div
                className={`flex-shrink-0 min-w-12 text-gray-500 dark:text-dark-100 select-none ${
                  props.disabled ? "opacity-50" : ""
                }`}
              >
                {start}
              </div>
            )}
            <input
              ref={(node) => {
                if (typeof ref === "function") {
                  ref(node);
                } else if (ref) {
                  ref.current = node;
                }
                inputRef.current = node;
              }}
              value={displayValue}
              placeholder={placeholder}
              type={password ? "password" : "text"}
              onChange={handleChange}
              onMouseDown={handleMouseDown}
              onTouchStart={handleTouchStart}
              onClick={handleClick}
              onFocus={handleFocus}
              onBlur={handleBlur}
              className={`${inputClass} ${
                fullWidth || (start && end) ? "w-full" : ""
              } ${start ? "pl-2" : ""} ${end ? "pr-2" : ""}`}
              {...props}
            />
            {end && (
              <div
                dir="ltr"
                className={`flex-shrink-0 min-w-12 text-gray-500 dark:text-dark-100 select-none text-left mr-1 flex items-center justify-start ${
                  props.disabled ? "opacity-50" : ""
                }`}
              >
                {end}
              </div>
            )}
          </div>
          {placeholder && (
            <AnimatePresence>
              {shouldFloatLabel && (
                <motion.label
                  key="floating-label"
                  variants={floatingLabelVariants}
                  initial="hidden"
                  animate="visible"
                  exit="hidden"
                  className={floatingLabelClass}
                  onClick={() => inputRef.current?.focus()}
                >
                  {placeholder}
                </motion.label>
              )}
            </AnimatePresence>
          )}
        </div>
        {helperText && (
          <p
            onClick={() => {
              if (isAutoComplete && handleCloseInput) {
                handleCloseInput();
              }
            }}
            className={`text-xs mt-1 ${
              error ? "text-red-400" : "text-gray-500"
            } ${props.disabled ? "opacity-50" : ""}`}
          >
            {helperText}
          </p>
        )}
        {children}
      </div>
    );
  }
);

Textfield.displayName = "Textfield";

export default Textfield;
