import { ChangeEventHandler, useCallback, useMemo, useRef } from 'react';

import { Country } from '../../constans/country';
import { countryForPhone } from '../../core/utils/countryForPhone';
import { useTestIdAttribute } from '../../hooks/useTestIdAttribute';
import { assertEmptyObject } from '../../utils/assertEmptyObject';
import { changeInputValue } from '../../utils/changeInputValue';
import { makeTestId } from '../../utils/makeTestId';
import { SupportedInputProps } from '../types';

import { CountryChoseSelect } from './components/CountryChoseSelect/CountryChoseSelect';
import { StyledField, StyledFieldContainer, TunedInput } from './styled';
import { phoneMask } from './utils/phoneMask';
import { replacePhoneCode } from './utils/replacePhoneCode';

export interface PhoneFieldProps extends SupportedInputProps {
  /** Phone number without spaces with plus */
  value?: string;
}

/**
 * Component that allow typing phone number.
 *
 * This component supports masks for known countries. Also, this component
 * supports change phone code by dropdown.
 *
 * ```tsx
 * import { PhoneField } from 'ui-kit';
 *
 * <PhoneField value="+11223412" onChange={console.log} />
 * ```
 */
export function PhoneField(props: PhoneFieldProps) {
  const {
    ariaInvalid,
    ariaLabel,
    ariaDescribedBy,
    ariaErrorMessage,
    onChange,
    className,
    value,
    disabled,
    id,
    placeholder,
    onBlur,
    ariaRequired,
    required,
    testId,
    ...rest
  } = props;
  assertEmptyObject(rest);

  const testIdAttribute = useTestIdAttribute();
  const country = useMemo(() => countryForPhone(value), [value]);
  const inputRef = useRef<HTMLInputElement>(null);

  const handleCountryItemClick = useCallback(
    (countryTo: Country) => {
      /* istanbul ignore else */
      if (inputRef.current) {
        const nextPhone = replacePhoneCode(value, country, countryTo);

        // Stupid MaskedInput remove +1 when you try to set it after +61.
        // To avoid it behaviour we will change phone always thought empty string.
        changeInputValue(inputRef.current, '');
        changeInputValue(inputRef.current, nextPhone);

        inputRef.current.focus();
      }
    },
    [country, value],
  );

  const handleChange: ChangeEventHandler<HTMLInputElement> = (event) => {
    if (onChange) {
      onChange(event.target.value);
    }
  };

  return (
    <StyledFieldContainer className={className} {...{ [testIdAttribute]: testId }}>
      <StyledField $disabled={disabled}>
        <CountryChoseSelect
          country={country}
          countryClick={handleCountryItemClick}
          disabled={!!disabled}
          testId={makeTestId(testId, 'country-select')}
        />
        <TunedInput
          ref={inputRef}
          ariaDescribedBy={ariaDescribedBy}
          ariaErrorMessage={ariaErrorMessage}
          ariaInvalid={!!ariaInvalid}
          ariaLabel={ariaLabel}
          ariaRequired={ariaRequired}
          disabled={disabled}
          guide={false}
          id={id}
          mask={phoneMask}
          onBlur={onBlur}
          onChange={handleChange}
          placeholder={placeholder}
          required={required}
          testId={makeTestId(testId, 'input')}
          value={value}
        />
      </StyledField>
    </StyledFieldContainer>
  );
}
