/**
 * TEAM: frontend_infra
 * @flow
 */

import * as React from "react";
import {StyleSheet, css} from "aphrodite";

import {
  AsYouType,
  getCountryCallingCode,
  isSupportedCountry,
} from "libphonenumber-js";
import NumberFormatInput from "./NumberFormatInput";
import {countries} from "./constants/AddressOptionConstants.generated";
import Flag from "./Flag";
import SearchableSelectInput from "./select/SearchableSelectInput";
import Text from "./Text";
import Group from "./Group";
import {type Size} from "./sizes";

const PREFERRED_COUNTRIES = Object.keys(countries).filter(country =>
  isSupportedCountry(country)
);
const DEFAULT_COUNTRY = "US";
type Country = $Keys<typeof countries>;
const PATH = "https://assets.flexport.com/flags/svg/1/";
const EXTENSION = ".svg";
type PhoneNumberInputProps = {|
  /** note that this must be a string, and cannot be null or undefined. */
  +value: string,
  /** the size of the input */
  +size?: Size,
  /** called when the value of the input changes, passes value with countryCode */
  +onChange: string => void,
  /** the placeholder text that will be displayed when the input is empty */
  +placeholder?: string,
  /** whether the input is disabled or not */
  +disabled?: boolean,
  /** whether the input is readonly or not */
  +readOnly?: boolean,
  /** whether the input is invalid or not */
  +isInvalid?: boolean,
  /** whether the input is prefilled or not */
  +isPrefilled?: boolean,
  /** `ISO 3166-1 aplpha` 2 character country code default displayed */
  +defaultCountry?: Country,
  /** list of `ISO 3166-1 aplpha` 2 character country codes to display as options */
  +countryOptions?: $ReadOnlyArray<Country>,
|};

/**
 * @category Data entry
 * @short Choose country and input phone number
 * @brandStatus V3
 * @status Beta
 * The PhoneNumberInput component has a dropdown to select the country of phone number.
 * As the number is typed in, the country code is filled in and the number is formatted.
 * */
export default function PhoneNumberInput({
  value,
  onChange,
  size = "m",
  disabled = false,
  readOnly = false,
  isInvalid = false,
  isPrefilled = false,
  countryOptions = PREFERRED_COUNTRIES,
  defaultCountry = DEFAULT_COUNTRY,
}: PhoneNumberInputProps): React.Node {
  const [selected, setSelected] = React.useState(defaultCountry);
  const placeholder = getTemplateString(selected);
  const [phoneNumber, setPhoneNumber] = React.useState(value);

  const countryToCodeMap = countryOptions.reduce((acc, curr) => {
    acc[curr] = getCountryCallingCode(curr);
    return acc;
  }, {});

  const countryCodeToNameMap = countryOptions.reduce((acc, curr) => {
    acc[countries[curr].name] = countries[curr].code;
    return acc;
  }, {});
  const options = countryOptions.map(country => ({
    label: countries[country].name,
    value: countries[country].name,
    customView: (
      <div
        style={{
          padding: "8px",
          width: "230px",
        }}
      >
        <Flag countryCode={country} maxWidth={16} />
        {` ${countries[country].name}`}
        <span className={css(styles.option)}>
          <Text>{`+${countryToCodeMap[country] || ""}`}</Text>
        </span>
      </div>
    ),
    imageSrc: `${PATH}${countries[country].code}${EXTENSION}`,
  }));

  const handleDropdownChange = (countryName: ?string) => {
    const countryCode = countryName ? countryCodeToNameMap[countryName] : null;
    setSelected(countryCode || defaultCountry);
    if (countryCode) {
      setPhoneNumber(`+${getCountryCallingCode(countryCode)}`);
    }
  };

  const setCountry = (newNumber: string) => {
    const numberOnlyDigit = newNumber.replace(/\D/g, "");
    const filterCountryCode = Array.from(Object.keys(countryToCodeMap)).filter(
      key =>
        `${countryToCodeMap[key] || ""}` ===
        numberOnlyDigit.substring(0, countryToCodeMap[key].length)
    );
    if (filterCountryCode.length !== 0) {
      const countryOption = options.filter(country =>
        filterCountryCode.includes(countryCodeToNameMap[country.value])
      );
      if (/^\+1/.test(newNumber)) {
        // prioritize +1 as US
        setSelected("US");
      } else if (/^\+7/.test(newNumber)) {
        // prioritize +7 as RU
        setSelected("RU");
      } else {
        setSelected(countryCodeToNameMap[countryOption[0].value]);
      }
    }
  };

  const handleInputOnChange = (newNumber: string) => {
    setCountry(newNumber);
    setPhoneNumber(newNumber);
    onChange(newNumber);
  };

  return (
    <Group alignItems="center" gap={0}>
      <div className={css(styles.dropdown)}>
        <div className={css(styles.dropdownBox)}>
          <SearchableSelectInput
            isNullable={false}
            options={options}
            value={countries[selected].name}
            onChange={handleDropdownChange}
            placeholder=""
            showImage={true}
            size={size}
          />
        </div>
      </div>
      <div className={css(styles.phoneInput)}>
        <NumberFormatInput
          value={phoneNumber || ""}
          onChange={handleInputOnChange}
          isInvalid={isInvalid}
          disabled={disabled}
          placeholder={placeholder}
          readOnly={readOnly}
          isPrefilled={isPrefilled}
          size={size}
          format={placeholder.replace(/[0-9]/g, "#")}
        />
      </div>
    </Group>
  );
}

const getTemplateString = (countryCode: string) => {
  const ayt = new AsYouType(countryCode);
  const template = ayt.getTemplateForNumberFormatPattern(
    ayt.metadata.formats()[0]
  );
  return `+${getCountryCallingCode(countryCode) || ""} ${template.replace(
    /x/g,
    "0"
  )}`;
};

const styles = StyleSheet.create({
  dropdown: {
    display: "flex",
    alignItems: "center",
    width: 50,
  },
  dropdownBox: {
    minWidth: 50,
    marginRight: -2,
    zIndex: 1,
    ":nth-child(1n) > div > div > div > div > input": {
      paddingLeft: 0,
    },
    ":nth-child(1n) > div > div > div > div > input::placeholder": {
      color: "white",
    },
  },
  option: {
    float: "right",
  },
  phoneInput: {
    ":nth-child(1n) > div > input:focus": {
      zIndex: 1,
    },
  },
});
