import React, { FC, useState } from 'react';
import Form from '../../blocks/Form';
import Input from '../../blocks/Input';
import css from '../FormCustomerDetails/index.module.css';
import 'font-awesome/css/font-awesome.min.css';
import PlacesAutocomplete, {
  geocodeByAddress,
} from 'react-places-autocomplete';
import {
  getStreetNumber,
  getCity,
  getStreetName,
  getZipCode,
  autocompleteDebounce,
  renderAutocomplete,
} from '../../helpers/addressHelper';

export interface FormCustomerBillingDetailsValues {
  firstName: string;
  lastName: string;
  street: string;
  streetNr: string;
  zip: string;
  city: string;
  company: string;
  countryCode: string;
  country: string;
  additional: string;
}

export interface FormCustomerBillingDetailsLabels {
  firstName: string;
  lastName: string;
  street: string;
  streetNr: string;
  zip: string;
  city: string;
  company: string;
  country: string;
  additional: string;
}

export interface FormCustomerBillingDetailsErrors {
  firstName?: string;
  lastName?: string;
  street: string;
  streetNr: string;
  zip: string;
  city: string;
  company?: string;
  additional: string;
}

export interface FormCustomerBillingDetailsTouched {
  [key: string]: unknown;
}

export interface FormCustomerBillingDetailsProps {
  values: FormCustomerBillingDetailsValues;
  touched: FormCustomerBillingDetailsTouched;
  errors: FormCustomerBillingDetailsErrors;
  labels: FormCustomerBillingDetailsLabels;
  handleChange: (e) => void;
  handleBlur: (e) => void;
  status?: {
    msg: string;
  };
  setFieldValue: (field, value) => void;
  setFieldTouched: (field, touched) => void;
  region: string;
  checkIfKeyBoardOpen?: (e) => void;
}

const FormCustomerBillingDetails: FC<FormCustomerBillingDetailsProps> = ({
  values,
  touched,
  errors,
  handleChange,
  handleBlur,
  labels,
  status,
  setFieldValue,
  setFieldTouched,
  region,
  checkIfKeyBoardOpen,
}) => {
  const [isAutocomplete, setAutocomplete] = useState('');

  const handleSelect = async (value): Promise<void> => {
    const results = await geocodeByAddress(value);
    const addressArray = results[0].address_components;
    const cityName = getCity(addressArray);
    const zip = getZipCode(addressArray);
    const streetName = getStreetName(addressArray);
    const streetNumber = getStreetNumber(addressArray);

    if (cityName) setFieldValue('city', cityName);
    if (zip) setFieldValue('zip', zip);
    if (streetName) setFieldValue('street', streetName);
    setFieldValue('streetNr', streetNumber ? streetNumber : values.streetNr);

    // Delay validation because value is no set yet
    setTimeout(() => {
      if (cityName) setFieldTouched('city', true);
      if (zip) setFieldTouched('zip', true);
      if (streetName) setFieldTouched('street', true);
      if (streetNumber) setFieldTouched('streetNr', true);
    });
  };

  const handleSelectValue = async (value): Promise<void> => {
    const results = await geocodeByAddress(value);
    const addressArray = results[0].address_components;
    const cityName = getCity(addressArray);
    const zip = getZipCode(addressArray);

    if (cityName) setFieldValue('city', cityName);
    if (zip) setFieldValue('zip', zip);

    setTimeout(() => {
      if (cityName) setFieldTouched('city', true);
      if (zip) setFieldTouched('zip', true);
    });
  };

  const searchOptionsStreet = {
    componentRestrictions: {
      country: [region],
    },
    types: ['geocode'],
  };

  const searchOptions = {
    componentRestrictions: {
      country: [region],
    },
    types: ['(regions)'],
  };

  const mapsAvailable = (): boolean => {
    return !!window['google'];
  };

  return (
    <Form novalidate>
      <div className={css.formRegister__input}>
        <Input
          style={'booking'}
          name="firstName"
          type="text"
          label={labels.firstName}
          required
          onChange={handleChange}
          onBlur={handleBlur}
          value={values.firstName}
          error={touched.firstName && errors.firstName}
          isKeyBoardOpen={checkIfKeyBoardOpen}
        />
      </div>

      <div className={css.formRegister__input}>
        <Input
          style={'booking'}
          name="lastName"
          autocomplete="family-name"
          type="text"
          label={labels.lastName}
          required
          onChange={handleChange}
          onBlur={handleBlur}
          value={values.lastName}
          error={touched.lastName && errors.lastName}
          isKeyBoardOpen={checkIfKeyBoardOpen}
        />
      </div>

      <div className={css.formRegister__input}>
        <Input
          style={'booking'}
          name="company"
          type="text"
          label={labels.company}
          onChange={handleChange}
          onBlur={handleBlur}
          value={values.company}
          error={touched.company && errors.company}
          isKeyBoardOpen={checkIfKeyBoardOpen}
          isOptionalDisplay={true}
        />
      </div>

      <div className={css.formRegister__inputStreet}>
        {mapsAvailable() && (
          <PlacesAutocomplete
            value={values.street}
            onChange={(val): void => {
              autocompleteDebounce(
                isAutocomplete,
                setAutocomplete,
                'street',
                500,
              );
              setFieldValue('street', val);
              setTimeout(() => setFieldTouched('street', true));
            }}
            onSelect={handleSelect}
            searchOptions={searchOptionsStreet}
            shouldFetchSuggestions={isAutocomplete == 'street'}
          >
            {({
              getInputProps,
              suggestions,
              getSuggestionItemProps,
            }): JSX.Element => {
              return renderAutocomplete(
                checkIfKeyBoardOpen,
                getInputProps,
                suggestions,
                getSuggestionItemProps,
                labels.street,
                values.street,
                touched.street,
                errors.street,
                setFieldTouched,
                'text',
                'street',
                'street-address',
              );
            }}
          </PlacesAutocomplete>
        )}

        <div className={css.formRegister__input}>
          <Input
            style={'booking'}
            name="streetNr"
            autocomplete="street-address"
            type="text"
            label={labels.streetNr}
            required
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.streetNr}
            error={touched.streetNr && errors.streetNr}
            isKeyBoardOpen={checkIfKeyBoardOpen}
          />
        </div>
      </div>

      <div className={css.formRegister__input}>
        <Input
          style={'booking'}
          name="additional"
          type="text"
          label={labels.additional}
          onChange={handleChange}
          onBlur={handleBlur}
          value={values.additional}
          error={touched.additional && errors.additional}
          isKeyBoardOpen={checkIfKeyBoardOpen}
          isOptionalDisplay={true}
        />
      </div>

      <div className={css.formRegister__inputCity}>
        {mapsAvailable() && (
          <PlacesAutocomplete
            value={values.zip}
            onChange={(val): void => {
              autocompleteDebounce(isAutocomplete, setAutocomplete, 'zip', 500);
              setFieldValue('zip', val);
              setTimeout(() => setFieldTouched('zip', true));
            }}
            onSelect={handleSelectValue}
            searchOptions={searchOptions}
            shouldFetchSuggestions={isAutocomplete == 'zip'}
          >
            {({
              getInputProps,
              suggestions,
              getSuggestionItemProps,
            }): JSX.Element => {
              return renderAutocomplete(
                checkIfKeyBoardOpen,
                getInputProps,
                suggestions,
                getSuggestionItemProps,
                labels.zip,
                values.zip,
                touched.zip,
                errors.zip,
                setFieldTouched,
                'text',
                'zip',
                'postal-code',
              );
            }}
          </PlacesAutocomplete>
        )}
        {mapsAvailable() && (
          <PlacesAutocomplete
            value={values.city}
            onChange={(val): void => {
              autocompleteDebounce(isAutocomplete, setAutocomplete, 'zip', 500);
              setFieldValue('city', val);
              setTimeout(() => setFieldTouched('city', true));
            }}
            onSelect={handleSelectValue}
            searchOptions={searchOptions}
            shouldFetchSuggestions={isAutocomplete == 'city'}
          >
            {({
              getInputProps,
              suggestions,
              getSuggestionItemProps,
            }): JSX.Element => {
              return renderAutocomplete(
                checkIfKeyBoardOpen,
                getInputProps,
                suggestions,
                getSuggestionItemProps,
                labels.city,
                values.city,
                touched.city,
                errors.city,
                setFieldTouched,
                'text',
                'city',
                'locality',
              );
            }}
          </PlacesAutocomplete>
        )}
      </div>

      {status && status.msg && (
        <div className={css.formRegister__messages}>{status.msg}</div>
      )}
    </Form>
  );
};

export default FormCustomerBillingDetails;
