import React, {useEffect, useMemo, useState} from 'react';
import {
  Keyboard,
  TextInput,
  TextInputProps,
  View,
  ViewStyle,
  FocusEvent,
  BlurEvent,
} from 'react-native';
import {useController} from 'react-hook-form';
import Text, {TextVariant} from '@components/Text';
import {TextVariantStyles} from '@components/Text/styles';
import InputContainer from '@components/InputContainer';
import {
  getFormattedPhoneNumber,
  getPhoneNumberMaxLength,
  getPhoneValues,
} from '@shared/utils/phone';
import {COUNTRIES, ICountry} from '@shared/countries';
import {REGEX_SPACE} from '@shared/regexs';
import {COLORS} from '@shared/colors';

import CountriesModal from './components/CountriesModal';
import DialCode from './components/DialCode';
import {styles} from './styles';

const DEFAULT_MAX_LENGTH = 15;

export interface Props
  extends Omit<TextInputProps, 'value' | 'onChangeText' | 'onChange'> {
  onChange: (value: string) => void;
  containerStyle?: ViewStyle;
  contentStyle?: ViewStyle;
  label?: string;
  showError?: boolean;
  error?: string;
  textVariant?: TextVariant;
  defaultCountryCode?: string;
}

const initialCountrySelected = COUNTRIES.at(0)!;

const getPhoneInitialValue = (defaultValue?: string) => () => {
  if (!defaultValue) {
    return '';
  }
  const values = getPhoneValues(
    `${!defaultValue.startsWith('+') ? '+' : ''}${defaultValue}`,
  );
  return values?.phone || '';
};
const getCountryInitialValue = (defaultValue?: string) => () => {
  if (!defaultValue) {
    return initialCountrySelected;
  }
  const values = getPhoneValues(
    `${!defaultValue.startsWith('+') ? '+' : ''}${defaultValue}`,
  );
  return values?.country || initialCountrySelected;
};

/**
 * @deprecated Use `_HuGo/Input/InputPhone` instead
 */
function PhoneInput({
  label,
  defaultValue,
  placeholder,
  onFocus,
  onBlur,
  containerStyle,
  contentStyle,
  style,
  error,
  onChange,
  defaultCountryCode,
  editable = true,
  showError = true,
  textVariant = 'body1',
  placeholderTextColor = COLORS.DISABLED,
  numberOfLines = 1,
  ...props
}: Props) {
  const [focused, setFocused] = useState<boolean>(false);
  const [showCountries, setShowCountries] = useState<boolean>(false);
  const [countrySelected, setCountrySelected] = useState(
    getCountryInitialValue(defaultValue),
  );
  const [phoneNumber, setPhoneNumber] = useState(
    getPhoneInitialValue(defaultValue),
  );
  // Text input with format
  const formattedPhone = useMemo(() => {
    return getFormattedPhoneNumber(countrySelected.dialCode, phoneNumber);
  }, [countrySelected, phoneNumber]);

  // Max length for text input
  const maxLength = useMemo(() => {
    try {
      const max = getPhoneNumberMaxLength(countrySelected.code);
      const whiteSpacesCount = (formattedPhone?.split?.(' ')?.length || 1) - 1;
      return (max || DEFAULT_MAX_LENGTH) + whiteSpacesCount;
    } catch (e) {
      return DEFAULT_MAX_LENGTH;
    }
  }, [countrySelected, formattedPhone]);

  const handlePickerPress = () => {
    Keyboard.dismiss();
    setShowCountries(true);
  };

  const handleCountrySelect = (country: ICountry) => {
    setShowCountries(false);
    setCountrySelected(country);
    setPhoneNumber('');
  };

  const handleModalClose = () => {
    setShowCountries(false);
  };

  const onTextBlur = (e: BlurEvent) => {
    setFocused(false);
    onBlur?.(e);
  };

  const handleInputFocus = (e: FocusEvent) => {
    setFocused(true);
    setShowCountries(false);
    onFocus?.(e);
  };

  // Effect to update form field value
  useEffect(() => {
    if (countrySelected.dialCode && phoneNumber) {
      onChange(
        `${countrySelected.dialCode}${phoneNumber}`.replace(REGEX_SPACE, ''),
      );
    } else {
      onChange('');
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [countrySelected, phoneNumber]);

  // Effect to set default country code
  useEffect(() => {
    if (defaultCountryCode) {
      setCountrySelected(
        COUNTRIES.find(country => country.code === defaultCountryCode) ||
          initialCountrySelected,
      );
    }
  }, [defaultCountryCode]);

  return (
    <View style={[styles.container, containerStyle]}>
      {!!label && (
        <Text variant="caption" style={styles.label}>
          {label}
        </Text>
      )}
      <View
        style={[
          styles.content,
          {
            borderColor: focused
              ? COLORS.PRIMARY_BORDER
              : error
              ? COLORS.ERROR
              : COLORS.DARK_GRAY,
            backgroundColor: COLORS.WHITE,
          },
          contentStyle,
        ]}>
        <DialCode
          countrySelected={countrySelected}
          onPress={handlePickerPress}
          disabled={!editable}
        />
        <TextInput
          value={formattedPhone}
          onChangeText={setPhoneNumber}
          numberOfLines={numberOfLines}
          maxLength={maxLength}
          multiline={false}
          keyboardType="phone-pad"
          inputMode="numeric"
          onBlur={onTextBlur}
          onFocus={handleInputFocus}
          defaultValue={defaultValue}
          placeholderTextColor={placeholderTextColor}
          placeholder={placeholder || '123 123 123'}
          style={[TextVariantStyles[textVariant], styles.textInput, style]}
          {...props}
        />
      </View>
      {showError && (
        <Text variant="caption" style={styles.error}>
          {error || ' '}
        </Text>
      )}
      <CountriesModal
        isVisible={showCountries}
        onClose={handleModalClose}
        onSelect={handleCountrySelect}
        countrySelected={countrySelected}
      />
    </View>
  );
}

interface PhoneInputControllerProps
  extends Omit<Props, 'defaultValue' | 'onChange'> {
  name: string;
  defaultValue?: Nullable<Date>;
}

export const PhoneInputController = ({
  name,
  defaultValue,
  ...props
}: PhoneInputControllerProps) => {
  const {field, fieldState} = useController({
    name,
    defaultValue,
  });

  return (
    <InputContainer errorMessage={fieldState.error?.message}>
      <PhoneInput
        {...props}
        defaultValue={field.value}
        onChange={field.onChange}
      />
    </InputContainer>
  );
};

export default PhoneInput;
