"use strict";

/* eslint-disable functional/immutable-data */
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { AccessibilityInfo, Platform, Pressable, StyleSheet, TextInput, View } from "react-native";
import LinearGradient from "react-native-linear-gradient";
import Animated, { Easing, interpolateColor, useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";
import { useIONewTypeface, useIOTheme } from "../../context";
import { IOColors, hexToRgba } from "../../core";
import { useIOFontDynamicScale } from "../../utils/accessibility";
import { IOMaxFontSizeMultiplier, makeFontStyleObject } from "../../utils/fonts";
import { getInputPropsByType } from "../../utils/textInput";
import { Icon } from "../icons";
import { HSpacer } from "../layout";
import { BodySmall } from "../typography";
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
const inputMarginTop = 16;
const inputHeight = 60;
const inputPaddingHorizontal = 12;
const inputPaddingVertical = 8;
const inputRadius = 8;
const inputTransitionDuration = 250;
const inputLabelScaleFactor = 0.75; /* 16pt becomes 12pt */
const inputLabelFontSize = 16;
const inputDisabledOpacity = 0.5;
const inputRightElementMargin = 8;
const iconSize = 24;
const iconMargin = 8;
const styles = StyleSheet.create({
  textInput: {
    flexDirection: "row",
    alignItems: "center",
    height: inputHeight,
    paddingVertical: inputPaddingVertical
  },
  textInputOuterBorder: {
    ...StyleSheet.absoluteFillObject,
    borderRadius: inputRadius,
    borderCurve: "continuous",
    borderWidth: 1
  },
  textInputInnerBorder: {
    ...StyleSheet.absoluteFillObject,
    borderRadius: inputRadius,
    borderCurve: "continuous",
    borderWidth: 2
  },
  textInputStyle: {
    flexGrow: 1,
    flexShrink: 1,
    /* The following `paddingVertical` property fixes a weird bug on
    Android where the text input scrolls, if the user apply some
    gestures on it with keyboard open */
    paddingVertical: 0,
    marginTop: inputMarginTop,
    height: "100%",
    /* Slightly move the input on the left on Android
       to align to the label */
    ...(Platform.OS === "android" && {
      marginLeft: -4
    })
  },
  textInputLabelWrapper: {
    position: "absolute",
    zIndex: 10,
    bottom: 0,
    top: 0,
    justifyContent: "center"
  }
});
const HelperRow = ({
  value,
  counterLimit,
  bottomMessage,
  bottomMessageColor,
  inputType,
  textInputProps
}) => {
  const theme = useIOTheme();
  const valueCount = inputType === "default" ? value.length : value.replace(/\s/g, "").length;
  const helperAccessibilityLabel = useMemo(() => {
    if (textInputProps?.keyboardType === "numeric") {
      return `${value.split("").join(" ")}, ${valueCount} / ${counterLimit}`;
    }
    return `${value}, ${valueCount}`;
  }, [value, valueCount, counterLimit, textInputProps]);
  const bottomMessageColorDefault = theme["textBody-tertiary"];
  const bottomMessageColorValue = bottomMessageColor ?? bottomMessageColorDefault;
  const helperRowStyle = useMemo(() => {
    if (counterLimit && bottomMessage) {
      return {
        justifyContent: "space-between"
      };
    }
    if (counterLimit) {
      return {
        justifyContent: "flex-end"
      };
    }
    if (bottomMessage) {
      return {
        justifyContent: "flex-start"
      };
    }
    return {};
  }, [counterLimit, bottomMessage]);
  return /*#__PURE__*/_jsxs(View, {
    style: [{
      flexDirection: "row",
      alignItems: "center",
      paddingHorizontal: inputPaddingHorizontal
    }, helperRowStyle]
    // in case of error message the element should be ignored by VO or Talkback
    ,
    accessibilityElementsHidden: bottomMessageColor === "error-600",
    importantForAccessibility: bottomMessageColor === "error-600" ? "no-hide-descendants" : "auto",
    children: [bottomMessage && /*#__PURE__*/_jsx(BodySmall, {
      weight: "Regular",
      color: bottomMessageColorValue,
      children: bottomMessage
    }), counterLimit && /*#__PURE__*/_jsx(BodySmall, {
      accessibilityLiveRegion: "polite",
      weight: "Regular",
      accessibilityLabel: helperAccessibilityLabel,
      color: bottomMessageColorValue,
      children: `${valueCount} / ${counterLimit}`
    })]
  });
};
export const TextInputBase = ({
  disabled = false,
  placeholder,
  value = "",
  onChangeText,
  accessibilityLabel,
  accessibilityHint,
  textInputProps,
  inputType = "default",
  status,
  icon,
  rightElement,
  counterLimit,
  accessibilityAnnounceLimitReached,
  bottomMessage,
  bottomMessageColor,
  onBlur,
  onFocus,
  isPassword,
  autoFocus,
  testID
}) => {
  const inputRef = useRef(null);
  const [inputStatus, setInputStatus] = useState(disabled ? "disabled" : "initial");
  const focusedState = useSharedValue(0);
  const {
    newTypefaceEnabled
  } = useIONewTypeface();
  const {
    dynamicFontScale,
    spacingScaleMultiplier
  } = useIOFontDynamicScale();
  const theme = useIOTheme();
  const iconColor = theme["icon-decorative"];
  const inputLabelColor = IOColors[theme["textInputLabel-default"]];
  const inputTextColor = IOColors[theme["textInputValue-default"]];
  const inputDisabledTextColor = IOColors[theme["textInputValue-disabled"]];

  /* Get the label width to enable the correct translation */
  const [labelWidth, setLabelWidth] = useState(0);
  const getLabelWidth = ({
    nativeEvent
  }) => {
    setLabelWidth(nativeEvent.layout.width);
  };

  /* Set `inputStatus` when `status` changes
     (e.g. when it's passed as a prop) */
  useEffect(() => {
    if (status) {
      setInputStatus(status);
    }
  }, [status]);

  /* Visual attributes */
  const appBackground = IOColors[theme["appBackground-primary"]];
  const borderColorMap = useMemo(() => ({
    initial: IOColors[theme["textInputBorder-default"]],
    disabled: IOColors[theme["textInputBorder-default"]],
    focused: IOColors[theme["interactiveElem-default"]],
    error: IOColors[theme.errorText]
  }), [theme]);
  const easingConf = {
    duration: inputTransitionDuration,
    easing: Easing.inOut(Easing.cubic)
  };
  const animatedLabelStyle = useAnimatedStyle(() => {
    const enableTransition = focusedState.value || value.length > 0;
    return {
      transform: [{
        /* Since we can't have RN 0.73 yet, we use this calculation
        to simulate `transformOrigin: left` */
        translateX: withTiming(enableTransition ? -labelWidth * (1 - inputLabelScaleFactor) / 2 : 0, easingConf)
      }, {
        translateY: withTiming(enableTransition ? -12 : 0, easingConf)
      }, {
        scale: withTiming(enableTransition ? inputLabelScaleFactor : 1, easingConf)
      }]
    };
  });

  /* Interpolate border color based on input status,
     but not apply the transition on `focus` state
     because it's already managed by the
     `animatedInnerBorderStyle` */
  const animatedOuterBorderStyle = useAnimatedStyle(() => ({
    borderColor: inputStatus !== "focused" ? interpolateColor(1, [0, 1], [borderColorMap.initial, borderColorMap[inputStatus]]) : borderColorMap.initial
  }));
  const animatedInnerBorderStyle = useAnimatedStyle(() => ({
    opacity: withTiming(focusedState.value ? 1 : 0, easingConf)
  }));
  const onTextInputPress = () => {
    if (disabled) {
      return;
    }
    focusedState.value = 1;
    setInputStatus("focused");
    inputRef?.current?.focus();
  };
  const onChangeTextHandler = useCallback(text => {
    const actualTextLength = inputType !== "default" ? text.replace(/\s/g, "").length : text.length;

    // Notify the user when the limit is reached
    // This is only for iOS, as Android handles it via accessibilityLiveRegion
    if (counterLimit && actualTextLength >= counterLimit && accessibilityAnnounceLimitReached && Platform.OS === "ios") {
      AccessibilityInfo.announceForAccessibility(accessibilityAnnounceLimitReached);
    }
    if (counterLimit && actualTextLength > counterLimit) {
      return;
    }
    if (inputType !== "default") {
      // necessary to omit whitespaces added by the valueFormat function
      const formattedText = text.replace(/\s/g, "");
      onChangeText(formattedText);
    } else {
      onChangeText(text);
    }
  }, [counterLimit, onChangeText, inputType, accessibilityAnnounceLimitReached]);
  const onBlurHandler = useCallback(() => {
    focusedState.value = 0;
    onBlur?.();
    setInputStatus("initial");
  }, [focusedState, onBlur]);
  const onFocusHandler = () => {
    focusedState.value = 1;
    onFocus?.();
    setInputStatus("focused");
  };
  const derivedInputProps = useMemo(() => getInputPropsByType(inputType), [inputType]);
  const inputValue = useMemo(() => derivedInputProps && derivedInputProps.valueFormat ? derivedInputProps.valueFormat(value) : value, [value, derivedInputProps]);

  // Calculate the adjusted maxLength to account for spaces
  const adjustedMaxLength = useMemo(() => {
    if (counterLimit && derivedInputProps && derivedInputProps.valueFormat) {
      const spacesCount = Math.floor(counterLimit / 4);
      return counterLimit + spacesCount;
    }
    return counterLimit;
  }, [counterLimit, derivedInputProps]);
  return /*#__PURE__*/_jsxs(_Fragment, {
    children: [/*#__PURE__*/_jsxs(Pressable, {
      onPress: onTextInputPress,
      style: [inputStatus === "disabled" ? {
        opacity: inputDisabledOpacity
      } : {}, styles.textInput, {
        paddingHorizontal: inputPaddingHorizontal * dynamicFontScale * spacingScaleMultiplier
      }],
      accessible: false,
      accessibilityRole: "none",
      importantForAccessibility: "no",
      children: [/*#__PURE__*/_jsx(Animated.View, {
        style: [styles.textInputOuterBorder, animatedOuterBorderStyle]
      }), !disabled && /*#__PURE__*/_jsx(Animated.View, {
        style: [{
          borderColor: borderColorMap.focused
        }, styles.textInputInnerBorder, animatedInnerBorderStyle]
      }), icon && /*#__PURE__*/_jsxs(_Fragment, {
        children: [/*#__PURE__*/_jsx(Icon, {
          allowFontScaling: true,
          name: icon,
          color: iconColor,
          size: iconSize
        }), /*#__PURE__*/_jsx(HSpacer, {
          allowScaleSpacing: true,
          size: iconMargin
        })]
      }), /*#__PURE__*/_jsx(TextInput, {
        ref: inputRef,
        testID: testID,
        ...(derivedInputProps ? derivedInputProps.textInputProps : textInputProps),
        accessible: true,
        importantForAccessibility: "yes",
        accessibilityElementsHidden: false,
        editable: !disabled,
        secureTextEntry: isPassword,
        disableFullscreenUI: true,
        accessibilityState: {
          disabled
        },
        accessibilityLabel: accessibilityLabel ?? placeholder,
        accessibilityHint: accessibilityHint,
        accessibilityLiveRegion: "polite",
        selectionColor: IOColors[theme["interactiveElem-default"]] // Caret on iOS
        ,
        cursorColor: IOColors[theme["interactiveElem-default"]] // Caret Android
        ,
        maxLength: adjustedMaxLength,
        maxFontSizeMultiplier: IOMaxFontSizeMultiplier,
        onBlur: onBlurHandler,
        onFocus: onFocusHandler,
        blurOnSubmit: true,
        onChangeText: onChangeTextHandler,
        style: [{
          ...makeFontStyleObject(inputLabelFontSize, newTypefaceEnabled ? "Titillio" : "TitilliumSansPro", undefined, "Regular")
        }, styles.textInputStyle, !disabled ? {
          color: inputTextColor
        } : {
          color: inputDisabledTextColor
        }],
        autoFocus: autoFocus,
        value: inputValue
      }), /*#__PURE__*/_jsx(Animated.View, {
        pointerEvents: "none",
        style: [styles.textInputLabelWrapper, {
          paddingHorizontal: inputPaddingHorizontal * dynamicFontScale * spacingScaleMultiplier
        }, icon ? {
          left: (iconSize + iconMargin) * dynamicFontScale * spacingScaleMultiplier
        } : {}],
        children: /*#__PURE__*/_jsx(Animated.Text, {
          onLayout: getLabelWidth,
          numberOfLines: 1,
          accessible: false,
          maxFontSizeMultiplier: IOMaxFontSizeMultiplier,
          style: [{
            ...makeFontStyleObject(inputLabelFontSize, newTypefaceEnabled ? "Titillio" : "TitilliumSansPro", undefined, "Regular"),
            color: inputLabelColor
          }, animatedLabelStyle],
          children: placeholder
        })
      }), rightElement && /*#__PURE__*/_jsxs(Animated.View, {
        style: {
          alignSelf: "stretch",
          overflow: "visible",
          justifyContent: "center"
        },
        children: [/*#__PURE__*/_jsx(LinearGradient, {
          useAngle: true,
          angle: 90,
          style: {
            width: inputRightElementMargin * 3,
            position: "absolute",
            left: -inputRightElementMargin * 3,
            top: 0,
            bottom: 0
          },
          colors: [hexToRgba(appBackground, 0), appBackground]
        }), /*#__PURE__*/_jsx(HSpacer, {
          size: inputRightElementMargin
        }), rightElement]
      })]
    }), (bottomMessage || counterLimit) && /*#__PURE__*/_jsx(HelperRow, {
      value: inputValue,
      bottomMessage: bottomMessage,
      bottomMessageColor: bottomMessageColor,
      counterLimit: counterLimit,
      inputType: inputType,
      textInputProps: textInputProps
    })]
  });
};
//# sourceMappingURL=TextInputBase.js.map