import { FC, useEffect, useState } from 'react';
import { FormFieldProps } from 'mystique/registry/FieldRegistry';
import {
  FormControl,
  FormControlLabel,
  FormHelperText,
  InputLabel,
  makeStyles,
  MenuItem,
  Paper,
  Radio,
  RadioGroup,
  Select,
  Switch,
  TextField,
} from '@material-ui/core';
import { useI18n } from 'mystique/hooks/useI18n';
import { Theme } from '@material-ui/core/styles';
import { Autocomplete } from '@material-ui/lab';
import { getQuery } from 'mystique/hooks/getQuery';
import { useSettings } from 'mystique/hooks/useSettings';
import { useQuery } from 'mystique/hooks/useQuery';
import { Loading } from 'mystique/components/Loading';
import _ from 'lodash';
import { editLocationCountriesSettingName } from '../../../constants/SettingNames';

interface Location {
  node: {
    ref: string;
    name: string;
  };
}

const locationsQuery = `
  query getLocations {
    locations(first: 5000) {
      edges {
        node {
          ref
          name
        }
      }
    }
  }
`;

const orderQuery = `
  query getOrderById($id: ID!) {
    orderById(id: $id) {
      customer {
        firstName
        lastName
      }
    }
  }
`;

const customerAddressQuery = `
  query getAddressForCustomer($name: String) {
    customerAddresses(name: [$name]) {
      edges {
        node {
          name
          companyName
          city
          street
          country
          postcode
          timeZone
          latitude
          longitude
        }
      }
    }
  }
`;

interface PickupLocation {
  companyName?: string;
  name?: string;
  street?: string;
  city?: string;
  state?: string;
  postcode?: string;
  region?: string;
  country?: string;
  latitude?: number;
  longitude?: number;
  timeZone?: string;
  lodgedLocation?: Location;
}

export const PickupLocationSelector: FC<FormFieldProps<any>> = ({
  lastSubmit,
  onChange,
  entityContext,
}) => {
  const classes = useStyles();
  const { translateOr } = useI18n();

  // error states
  const [errorStreet, setErrorStreet] = useState<boolean>(false);
  const [errorLodgedLocation, setErrorLodgedLocation] =
    useState<boolean>(false);

  // state for the information on the view
  const [pickupLocation, setPickupLocation] =
    useState<PickupLocation | undefined>();

  const [option, setOption] = useState<'customer' | 'store'>('customer');
  const [useCustomerAddress, setUseCustomerAddress] = useState<boolean>(false);
  const [customerAddress, setCustomerAddress] = useState<any>();
  const [countries, setCountries] = useState<string[]>([]);
  const [loading, setLoading] = useState<boolean>(true);
  const [hide, setHide] = useState<boolean>(false);

  useEffect(() => {
    const value =
      window.sessionStorage.getItem('HIDE_PICKUP_LOCATION') ?? 'true';
    setHide(value === 'true');
  }, [window.sessionStorage.getItem('HIDE_PICKUP_LOCATION')]);

  // load support information
  const countriesFromSetting = useSettings({
    setting: editLocationCountriesSettingName,
  });
  const [order] = useQuery(orderQuery, {
    'id': entityContext?.[0].entity.id,
  });
  const [locations] = useQuery(locationsQuery);

  const updateFieldForState = (event: any) => {
    setPickupLocation((prevState) => {
      return { ...prevState, [event.target.name]: event.target.value };
    });
  };

  useEffect(() => {
    // something is still loading - show loading icon
    setLoading(
      countriesFromSetting.setting.status == 'loading' ||
        order.fetching ||
        locations.fetching,
    );
  }, [countriesFromSetting, order, locations]);

  useEffect(() => {
    if (countriesFromSetting.setting.status == 'ok') {
      if (
        customerAddress &&
        customerAddress.country &&
        !(countriesFromSetting.setting.result.value as string[]).includes(
          customerAddress.country,
        )
      ) {
        // add address from customer entity even if it's not present in a static countries list
        setCountries([
          ...(countriesFromSetting.setting.result.value as string[]),
          customerAddress.country,
        ]);
      } else {
        setCountries([
          ...(countriesFromSetting.setting.result.value as string[]),
        ]);
      }
    }
  }, [countriesFromSetting, customerAddress]);

  useEffect(() => {
    // load customer address by searching 'name' = 'customer.firstName' + ' ' + 'customer.lastName'
    if (!order.fetching) {
      getQuery(customerAddressQuery, {
        name:
          (order.data as any).orderById.customer.firstName +
          ' ' +
          (order.data as any).orderById.customer.lastName,
      }).then((data) => {
        if (!data.error) {
          const [customerAddress] = (data.data as any).customerAddresses.edges;
          if (customerAddress) {
            setUseCustomerAddress(true);
            setCustomerAddress({
              companyName: customerAddress.node.companyName,
              name: customerAddress.node.name,
              street: customerAddress.node.street,
              city: customerAddress.node.city,
              postcode: customerAddress.node.postcode,
              state: customerAddress.node.state,
              country: customerAddress.node.country,
              region: customerAddress.node.region,
              longitude: customerAddress.node.longitude,
              latitude: customerAddress.node.latitude,
              timeZone: customerAddress.node.timeZone,
            });
          }
        }
      });
    }
  }, [order]);

  useEffect(() => {
    // push onChange with payload if no errors, otherwise push 'null'
    if (option === 'customer') {
      onChange(
        !_.isEmpty(pickupLocation?.street)
          ? {
            companyName: pickupLocation?.companyName,
            name: pickupLocation?.name,
            street: pickupLocation?.street,
            city: pickupLocation?.city,
            postcode: pickupLocation?.postcode,
            state: pickupLocation?.state,
            country: pickupLocation?.country,
            region: pickupLocation?.region,
            latitude: pickupLocation?.latitude,
            longitude: pickupLocation?.longitude,
            timeZone: pickupLocation?.timeZone,
          }
          : null,
      );
    } else {
      onChange(
        !_.isEmpty(pickupLocation?.lodgedLocation)
          ? {
            lodgedLocation: pickupLocation?.lodgedLocation?.node.ref,
          }
          : null,
      );
    }
  }, [pickupLocation, option, useCustomerAddress]);

  useEffect(() => {
    if (option === 'customer') {
      if (useCustomerAddress && customerAddress) {
        // preselect data from customer address
        setPickupLocation((prevState) => {
          return {
            ...prevState,
            ...customerAddress,
          } as PickupLocation;
        });
      } else {
        // clear fields that are not present on the view
        setPickupLocation((prevState) => {
          return {
            ...prevState,
            region: '',
            latitude: 1e-5,
            longitude: 1e-5,
            timeZone: '',
          } as PickupLocation;
        });
      }
    }
  }, [useCustomerAddress, customerAddress, option]);

  useEffect(() => {
    // recheck all error states after submit
    if (lastSubmit && lastSubmit > 0) {
      setErrorStreet(_.isEmpty(pickupLocation?.street));
      setErrorLodgedLocation(_.isEmpty(pickupLocation?.lodgedLocation));
    }
  }, [lastSubmit, pickupLocation?.street, pickupLocation?.lodgedLocation]);

  return (
    <>
      {loading ? (
        <Loading />
      ) : (
        !hide && (
          <Paper variant="elevation" className={classes.paper}>
            <FormControl
              fullWidth
              error={errorStreet}
              key="pickupLocation-form"
            >
              <RadioGroup value={option}>
                <FormControlLabel
                  className={classes.radio}
                  value="store"
                  control={<Radio />}
                  label={translateOr([
                    'fc.om.orders.detail.userAction.returnOrder.lodgedLocation.option',
                    'Option 1 - Enter location ref for return location',
                  ])}
                  onChange={() => setOption('store')}
                />
                <FormControlLabel
                  className={classes.radio}
                  value="customer"
                  control={<Radio />}
                  label={translateOr([
                    'fc.om.orders.detail.userAction.returnOrder.pickupLocation.option',
                    'Option 2 - Enter customer address for courier pickup',
                  ])}
                  onChange={() => setOption('customer')}
                />
              </RadioGroup>
              {option === 'customer' && (
                <>
                  <FormControlLabel
                    checked={useCustomerAddress}
                    onChange={(_e, value) => {
                      setUseCustomerAddress(value);
                    }}
                    control={<Switch color="primary" />}
                    label={translateOr([
                      'fc.om.orders.detail.userAction.returnOrder.pickupLocation.customerAddress.switch',
                      'Use customer address',
                    ])}
                    labelPlacement="end"
                  />
                  <TextField
                    key="customer-companyName-field"
                    name="companyName"
                    onChange={updateFieldForState}
                    value={pickupLocation?.companyName || ''}
                    disabled={useCustomerAddress}
                    label={translateOr([
                      'fc.om.orders.detail.userAction.returnOrder.pickupLocation.companyName.label',
                      'Company Name',
                    ])}
                    fullWidth
                  />
                  <TextField
                    className={classes.field}
                    key="customer-name-field"
                    name="name"
                    onChange={updateFieldForState}
                    value={pickupLocation?.name || ''}
                    disabled={useCustomerAddress}
                    label={translateOr([
                      'fc.om.orders.detail.userAction.returnOrder.pickupLocation.name.label',
                      'Name',
                    ])}
                    fullWidth
                  />
                  <TextField
                    error={errorStreet}
                    className={classes.field}
                    key="customer-street-field"
                    name="street"
                    onChange={(event) => {
                      updateFieldForState(event);
                      setErrorStreet(_.isEmpty(event.target.value));
                    }}
                    value={pickupLocation?.street || ''}
                    disabled={useCustomerAddress}
                    onBlur={() =>
                      setErrorStreet(_.isEmpty(pickupLocation?.street))
                    }
                    label={
                      translateOr([
                        'fc.om.orders.detail.userAction.returnOrder.pickupLocation.street.label',
                        'Street',
                      ]) + ' *'
                    }
                    fullWidth
                  />
                  <TextField
                    className={classes.field}
                    key="customer-city-field"
                    name="city"
                    onChange={updateFieldForState}
                    value={pickupLocation?.city || ''}
                    disabled={useCustomerAddress}
                    label={translateOr([
                      'fc.om.orders.detail.userAction.returnOrder.pickupLocation.city.label',
                      'City',
                    ])}
                    fullWidth
                  />
                  <TextField
                    className={classes.field}
                    key="customer-postcode-field"
                    name="postcode"
                    onChange={updateFieldForState}
                    value={pickupLocation?.postcode || ''}
                    disabled={useCustomerAddress}
                    label={translateOr([
                      'fc.om.orders.detail.userAction.returnOrder.pickupLocation.postcode.label',
                      'Postcode',
                    ])}
                    fullWidth
                  />
                  <TextField
                    className={classes.field}
                    key="customer-state-field"
                    name="state"
                    onChange={updateFieldForState}
                    value={pickupLocation?.state || ''}
                    disabled={useCustomerAddress}
                    label={translateOr([
                      'fc.om.orders.detail.userAction.returnOrder.pickupLocation.state.label',
                      'State',
                    ])}
                    fullWidth
                  />
                  <FormControl fullWidth className={classes.field}>
                    <InputLabel
                      id="country-select-label"
                      disabled={useCustomerAddress}
                    >
                      {translateOr([
                        'fc.om.orders.detail.userAction.returnOrder.pickupLocation.country.label',
                        'Country',
                      ])}
                    </InputLabel>
                    <Select
                      labelId="country-select-label"
                      id="customer-country-select"
                      name="country"
                      value={pickupLocation?.country || ''}
                      disabled={useCustomerAddress}
                      onChange={updateFieldForState}
                    >
                      {countries.map((value, idx) => {
                        return (
                          <MenuItem key={idx} value={value}>
                            {value}
                          </MenuItem>
                        );
                      })}
                    </Select>
                  </FormControl>
                  {errorStreet && (
                    <FormHelperText>
                      {translateOr([
                        'fc.om.orders.detail.userAction.returnOrder.pickupLocation.error',
                        'Enter customer address for courier pickup',
                      ])}
                    </FormHelperText>
                  )}
                </>
              )}
              {option === 'store' && (
                <>
                  <FormControl fullWidth error={errorLodgedLocation}>
                    <Autocomplete
                      options={(locations.data as any).locations.edges}
                      getOptionLabel={(location: any) =>
                        `${location.node.name} (${location.node.ref})`
                      }
                      onChange={(__, location) => {
                        setErrorLodgedLocation(_.isEmpty(location));
                        updateFieldForState({
                          target: {
                            value: location,
                            name: 'lodgedLocation',
                          },
                        });
                      }}
                      onBlur={() =>
                        setErrorLodgedLocation(
                          _.isEmpty(pickupLocation?.lodgedLocation),
                        )
                      }
                      value={pickupLocation?.lodgedLocation || null}
                      getOptionSelected={(option, value) =>
                        option.node.ref === value.node.ref
                      }
                      renderInput={(params) => (
                        <TextField
                          error={errorLodgedLocation}
                          {...params}
                          label={
                            translateOr([
                              'fc.om.orders.detail.userAction.returnOrder.lodgedLocation.label',
                              'Location ref for return location',
                            ]) + ' *'
                          }
                        />
                      )}
                    />
                    {errorLodgedLocation && (
                      <FormHelperText>
                        {translateOr([
                          'fc.om.orders.detail.userAction.returnOrder.lodgedLocation.error',
                          'Enter location ref for return location',
                        ])}
                      </FormHelperText>
                    )}
                  </FormControl>
                </>
              )}
            </FormControl>
          </Paper>
        )
      )}
    </>
  );
};

const useStyles = makeStyles((theme: Theme) => ({
  paper: {
    padding: theme.spacing(1),
  },
  field: {
    marginTop: theme.spacing(1),
  },
  radio: {
    '&:hover': {
      color: theme.palette.primary.main,
    },
  },
}));

export default PickupLocationSelector;
