import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import { useScreenContext } from "@/src/contexts/ScreenContext";
import { IInputProps } from "@/types/formInterfaces";
import { CalendarDays, X } from "lucide-react";
import React, { Fragment, useEffect, useRef, useState } from "react";
import { RiEyeCloseLine, RiEyeLine } from "react-icons/ri";
import { twMerge } from "tailwind-merge";
import * as yup from "yup";
import { FormatFields, GetForm } from "../../utils";
import { Calendar } from "../ui/calendar";
import Button from "./Button";
import InputImg from "./InputImg";
import InputMultipleImg from "./InputMultipleImg";

const Input = ({
  label,
  formulario: tmpForm,
  // name = "",
  name = " ",
  width,
  type,
  cols,
  rows,
  mascara,
  mascaraBlur,
  defaultValue,
  error,
  required,
  prefix,
  suffix,
  onChange,
  checked = false,
  equals,
  typeFile,
  isPassword = false,
  onInputProp,
  onRemoveFile,
  clearBtn = false,
  inputClassName = "",
  prefixWidth = "",
  dynamic = false,
  textSize = "text-md",
  labelSize = "text-md",
  schema,
  // value,
  ...rest
}: IInputProps) => {
  name = name ? name : " ";
  const inputRef = useRef<HTMLInputElement | HTMLTextAreaElement | null>(null);

  const [selectedDate, setSelectedDate] = useState<string>("");
  const [isChecked, setIsChecked] = useState<boolean>(
    typeof checked == "boolean" ? checked : checked == "1" || checked == "true",
  );
  const [visible, setVisible] = useState(false);

  const [suffixWidth, setSuffixWidth] = useState(0);
  const suffixRef = useRef<HTMLDivElement>(null);

  const { isMobile } = useScreenContext();

  const formulario = tmpForm || GetForm();
  const inputValue = formulario?.watch(name as any);
  // useEffect(() => {
  //   const nameValue = formulario.control._formValues[name];
  //   setInputValue(nameValue);
  // }, [formulario.watch(name as any)]);

  // useLayoutEffect(() => {
  useEffect(() => {
    if (suffixRef.current) {
      setSuffixWidth(suffixRef.current.offsetWidth);
    }
  }, [suffix, inputValue]);

  useEffect(() => {
    if (formulario) {
      const newSchema = formulario.yupSchema.fields;
      newSchema[name] = required ? yup.string().required(error) : yup.string();
      if (equals) {
        newSchema[name] = newSchema[name].oneOf(
          [yup.ref(equals), null],
          "Senhas devem ser iguais!",
        );
      }
      if (isPassword) {
        const upperCaseRegex = /(?=[A-Z])/;
        const lowerCaseRegex = /(?=[a-z])/;
        const numericRegex = /(?=.*[0-9])/;
        const magicRegex = /\W|_/;
        newSchema[name] = newSchema[name]
          .min(8, "Mínimo 8 caracteres")
          .matches(upperCaseRegex, "Ao menos um maiúsculo")
          .matches(lowerCaseRegex, "Ao menos um minúsculo")
          .matches(numericRegex, "Ao menos um número")
          .matches(magicRegex, "Um especial '!@#$'");
      }
      if (type == "email") {
        newSchema[name] = required
          ? yup.string().email("Escreva um email correto!").required(error)
          : yup.string().email("Escreva um email correto!");
      }
      // newSchema[name] = yup.string();
      // if (required) {
      //     newSchema[name] = newSchema[name].required(error);
      // }
      newSchema[name] = schema || newSchema[name];
      formulario.setYupSchema(yup.object().shape(newSchema));

      if (
        defaultValue &&
        (!Object.keys(formulario?.control?._formValues).includes(name) ||
          formulario?.control?._formValues[name] == undefined ||
          formulario?.control?._formValues[name] == "")
      ) {
        // eslint-disable-next-line react-hooks/exhaustive-deps
        defaultValue = handleFormatInput(false, defaultValue);
        formulario.setValue(name as never, defaultValue as never);
      }
    }

    return () => {
      if (dynamic) {
        formulario?.control.unregister([name] as never[], {
          keepValue: false,
          keepError: false,
        });
        // Remove a regra de validação desse campo do schema compartilhado,
        // senão ela continua exigida mesmo com o input desmontado.
        formulario?.setYupSchema((prevSchema: any) => {
          const newFields = { ...prevSchema?.fields };
          delete newFields[name];
          return yup.object().shape(newFields);
        });
      }
    };

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const handleEnterToNextField = (
    e: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>,
  ) => {
    if (e.key == "Enter") {
      e.preventDefault();
      const form = e.currentTarget.form;
      if (!form) return;

      const elements = Array.from(form.elements) as HTMLElement[];
      const index = elements.indexOf(e.currentTarget);

      for (let i = index + 1; i < elements.length; i++) {
        const next = elements[i] as HTMLElement;
        if (
          next &&
          typeof next.focus === "function" &&
          !next.hasAttribute("disabled")
        ) {
          next.focus();
          break;
        }
      }
    }
  };

  // const handleFormatInput = (event: React.ChangeEvent<HTMLInputElement>) => {
  const handleFormatInput = (event: any, value = "") => {
    const input = event.target;
    if (type !== "file") {
      if (input) {
        value = input.value;
      }
      switch (mascara) {
        case "telefone":
          value = FormatFields.formatarTelefone(value);
          break;
        case "data":
          value = FormatFields.formatarData(value);
          break;
        case "cep":
          value = FormatFields.formatarCep(value);
          break;
        case "cpf":
          value = FormatFields.formatarCPF(value);
          // value = FormatFields.formatarCPF(value);
          break;
        case "cnpj":
          value = FormatFields.formatarCNPJ(value);
          break;
        case "rg":
          value = FormatFields.formatarRG(value);
          break;
        case "numero":
          if (input) {
            if (value === null || value === undefined) {
              value = "0,00";
              break;
            }
            if (value === "") {
              value = "";
              break;
            }
            if (value.length === 1) {
              value = "0,0" + (FormatFields.formatarNumerico(value) || "0");
              break;
            }
          }
          value = FormatFields.formatarNumero(value);
          break;
        case "numerico":
          value = FormatFields.formatarNumerico(value);
          break;
        case "letras":
          value = FormatFields.formatarLetras(value);
          break;
        case "letrasNumeros":
          value = FormatFields.formatarLetrasNumeros(value);
          break;
        case "mesAno":
          value = FormatFields.formatarMesAno(value);
          break;
        case "numeroPreciso":
          value = FormatFields.formatarNumeroPreciso(value);
          break;
        case "hora":
          value = FormatFields.formatarHora(value);
          break;
        case "cpfCnpj":
          value = FormatFields.formatarCpfCnpj(value);
          break;
        case "porcentagem":
          value = FormatFields.formatarPorcentagem(value);
          break;
        case "monetario":
          value = FormatFields.formatarMoeda(value);
          break;
        default:
          break;
      }
      if (input) {
        if (["text", "search", "tel", "url", "password"].includes(input.type)) {
          // Input types that don't support selection (date, time, number, etc.)
          const unsupportedSelectionTypes = [
            "date",
            "time",
            "datetime-local",
            "month",
            "week",
            "number",
            "range",
            "color",
            "file",
            "checkbox",
            "radio",
            "submit",
            "button",
            "reset",
            "hidden",
          ];
          const inputType = (input as HTMLInputElement).type || type || "text";
          const supportsSelection =
            !unsupportedSelectionTypes.includes(inputType);

          if (supportsSelection) {
            const cursorStart = input.selectionStart ?? 0;

            // Diferença de tamanho após formatação
            const diff = value?.length - input?.value?.length;
            input.value = value;

            // Reposiciona cursor corretamente
            const newPosRaw = cursorStart + diff;

            const newPos = Math.max(0, Math.min(newPosRaw, value?.length || 0));

            requestAnimationFrame(() => {
              try {
                input.setSelectionRange(newPos, newPos);
              } catch (error) {
                // Silently fail if selection is not supported
              }
            });
          }
        } else {
          input.value = value;
        }

        if (onChange) {
          onChange(event);
        }
      }
    }

    return value;
  };
  const handleDateChange = (date: any) => {
    const formattedDate = FormatFields.formatarDataCalendar(date);
    setSelectedDate(formattedDate);
    formulario?.setValue(name as never, formattedDate as never);
  };

  inputClassName = twMerge(
    `w-full rounded border-[1.5px] inputDynamicSystem border-stroke bg-transparent  py-1.5 px-2 font-medium outline-none transition
  focus:border-primary active:border-primary disabled:cursor-default dark:border-form-strokedark
  dark:bg-form-input dark:focus:border-primary ${rest.disabled && "bg-gray-400"}`,
    inputClassName,
  );

  useEffect(() => {
    setIsChecked(
      typeof checked == "boolean"
        ? checked
        : checked == "1" || checked == "true",
    );
  }, [checked]);

  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault();
    const value = e.dataTransfer.getData("text/plain");

    if (inputRef.current) {
      const input = inputRef.current;
      const start = input.selectionStart || 0;
      const end = input.selectionEnd || 0;

      const currentValue = input.value;
      const newValue =
        currentValue.substring(0, start) + value + currentValue.substring(end);

      if (formulario) {
        formulario.setValue(name as never, newValue as never);
      } else {
        input.value = newValue;
      }

      // Atualiza a posição do cursor após a inserção
      input.selectionStart = start + value.length;
      input.selectionEnd = start + value.length;
    }
  };

  return rest.child ? (
    rest.child
  ) : (
    <div className={`${width ? width : "w-full "}`}>
      {label && type != "checkbox" && (
        <label
          htmlFor={name}
          className={twMerge(
            `mb-[10px] labelInputDynamic text-black dark:text-white whitespace-nowrap flex flex-row`,
            labelSize,
          )}
        >
          {typeof label == "string"
            ? label
                .split(" ")
                .map((str: string) =>
                  str.length > 3 ? str[0].toUpperCase() + str.slice(1) : str,
                )
                .join(" ")
            : label}{" "}
          <span className="text-[#ff2b2b] font-semibold ">
            {required && "*"}
          </span>
        </label>
      )}
      <div
        className={twMerge(
          `w-full flex items-center gap-1 relative flex-row${
            type == "password" && "-reverse"
          } align-middle`,
          rest.containerClassName,
        )}
      >
        {type == "file" ? (
          <InputImg
            typeFile={typeFile}
            onInputEvent={onInputProp}
            defaultImg={defaultValue}
            onRemoveFile={onRemoveFile}
          />
        ) : type === "multiple-file" ? (
          <InputMultipleImg
            typeFile={typeFile}
            onInputEvent={onInputProp}
            defaultImg={defaultValue}
            onRemoveFile={onRemoveFile}
          />
        ) : type !== "textarea" ? (
          type === "checkbox" ? (
            <div className="flex w-full">
              <label
                className={`flex cursor-pointer select-none items-center ${textSize}`}
              >
                <div className="relative">
                  <input
                    type="checkbox"
                    className={`sr-only ${textSize}`}
                    name={name}
                    // onKeyDown={handleEnterToNextField}
                    {...formulario?.register(name || " ")}
                    {...rest}
                    onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                      // O onChange customizado não pode engolir o do RHF:
                      // sem isso o checkbox não entra no submit.
                      if (formulario) {
                        formulario.setValue(
                          name as never,
                          e.target.checked as never,
                        );
                      }
                      setIsChecked(e.target.checked);
                      if (onChange) {
                        onChange(e);
                      }
                    }}
                    checked={isChecked}
                  />
                  <div
                    className={`mr-3 flex h-4 w-4 dark:border-white justify-center rounded border border-black ${
                      isChecked &&
                      "border-primary dark:border-primary bg-gray dark:bg-transparent"
                    }`}
                  >
                    <span
                      className={`h-2.5 w-2.5 rounded-sm ${isChecked && "bg-primary"}`}
                    ></span>
                  </div>
                </div>
                <div className={`${labelSize}`}>{label}</div>
              </label>
            </div>
          ) : (
            <Fragment>
              {type === "password" && (
                <div
                  className="align-middle absolute mr-2"
                  onClick={() => {
                    setVisible(!visible);
                  }}
                >
                  {visible ? <RiEyeLine /> : <RiEyeCloseLine />}
                </div>
              )}
              <input
                name={name}
                // onKeyDown={handleEnterToNextField}
                className={inputClassName}
                onInput={handleFormatInput}
                onDrop={handleDrop}
                onDragOver={(e) => e.preventDefault()}
                {...formulario?.register(name)}
                ref={(el) => {
                  // Registra no react-hook-form
                  if (formulario) {
                    const { ref } = formulario.register(name || " ");
                    ref(el);
                  }
                  // Atualiza nossa ref local
                  inputRef.current = el;
                }}
                type={type == "password" && visible ? "text" : type}
                style={{
                  paddingLeft: prefixWidth
                    ? prefixWidth
                    : `${prefix ? `${prefix.length * 10 + 12}` : "20"}px`,
                  paddingRight: `${type == "password" ? `${suffixWidth || 30}px` : `${suffixWidth || 20}px`}`,
                }}
                autoComplete="one-time-code"
                defaultValue={
                  !formulario
                    ? defaultValue && handleFormatInput(false, defaultValue)
                    : undefined
                }
                {...rest}
              />
              {mascara === "data" && (
                <Popover open={rest.disabled ? !rest.disabled : undefined}>
                  <PopoverTrigger asChild>
                    <CalendarDays
                      className="cursor-pointer dark:text-white text-black absolute right-2"
                      size={17}
                    />
                  </PopoverTrigger>
                  <PopoverContent style={{ zIndex: "9999" }}>
                    <Calendar
                      onSelect={handleDateChange}
                      mode="single"
                      initialFocus
                    />
                  </PopoverContent>
                </Popover>
              )}
              {clearBtn && (
                <Button
                  type="button"
                  className={`bg-danger flex hover:bg-danger hover:brightness-95 h-8 w-9 p-0  justify-center items-center text-black font-medium`}
                  onClick={(e: any) => {
                    formulario?.setValue(name as never, "" as never);
                    if (inputRef.current) {
                      inputRef.current.value = "";
                      inputRef.current.dispatchEvent(
                        new Event("input", { bubbles: true }),
                      );
                    }
                  }}
                >
                  <X size={15} color="white" />
                </Button>
              )}
            </Fragment>
          )
        ) : (
          <textarea
            name={name}
            className="w-full rounded border-[1.5px] border-stroke bg-transparent py-1.5 px-5 font-medium outline-none transition focus:border-primary active:border-primary disabled:cursor-default  dark:border-form-strokedark dark:bg-form-input dark:focus:border-primary"
            cols={cols ? cols : 25}
            rows={rows ? rows : 4}
            onInput={handleFormatInput}
            defaultValue={defaultValue}
            {...formulario?.register(name, {
              type: "string",
            })}
            {...rest}
          ></textarea>
        )}
        <span
          className="align-middle absolute ml-2"
          style={{
            userSelect: "none",
            // pointerEvents: "none"
          }}
        >
          {prefix}
        </span>
        {inputValue?.length > 0 && (
          <span
            className="align-middle absolute flex flex-row flex-nowrap pointer-events-none select-none"
            style={{
              userSelect: "none",
              paddingLeft: prefixWidth
                ? prefixWidth
                : `${prefix ? `${prefix.length * 10 + 12}` : "20"}px`,
              paddingRight: `${type == "password" ? "30px" : ""}`,
              width: "100%",
              // pointerEvents: "none"
            }}
          >
            <div
              className="align-middle flex flex-row flex-nowrap overflow-hidden w-full items-center whitespace-pre"
              style={{
                fontFeatureSettings: "normal",
                fontSize: isMobile ? "14px" : "16px",
              }}
            >
              <div
                className={`font-medium whitespace-pre text-transparent max-w-full overflow-hidden flex-shrink`}
              >
                {inputValue}
              </div>
              <div ref={suffixRef} className="flex-shrink-0">
                {inputValue?.length > 0 && suffix ? ` ${suffix} ` : ``}
              </div>
            </div>
          </span>
        )}
      </div>

      {formulario?.errors &&
        name &&
        formulario.errors[name] &&
        formulario.errors[name].message && (
          <span className="text-danger text-sm">
            {/* {formulario.errors[name].message} */}
            {(name && label
              ? formulario.errors[name].message.replaceAll(name, label)
              : formulario.errors[name].message
            )
              .split(" ")
              .map((str: string) =>
                str.length > 3 ? str[0].toUpperCase() + str.slice(1) : str,
              )
              .join(" ")}
          </span>
        )}
    </div>
  );
};

export default Input;
