import axios, { CancelTokenSource } from 'axios';
import { keys, set } from 'lodash';
import { AddressField, AppLocation, Place } from 'src/models';
import { addressComponentsMapper } from 'src/pages/captaciones/consts';
import { ref } from 'vue';

const API_KEY = process.env.GOOGLE_MAPS_API_KEY;

export function useGeocoding() {
  const options = ref<AppLocation[]>([]);
  const loading = ref(false);
  const cancelToken = ref<CancelTokenSource | null>();

  async function search(address: string) {
    if (cancelToken.value) cancelToken.value.cancel();
    cancelToken.value = axios.CancelToken.source();
    if (!address) return;
    const url = getURL(address);
    axios
      .post(url, undefined, { cancelToken: cancelToken.value.token })
      .then(({ data: { results } }: { data: { results: Place[] } }) => {
        const locations: AppLocation[] = results.map((place) => {
          const location = formatPlace(place);
          return location;
        });
        if (locations.length) {
          options.value = locations;
        }
      })
      .finally(() => {
        loading.value = false;
      });
  }

  const getURL = (address: string) => `https://maps.googleapis.com/maps/api/geocode/json?new_forward_geocoder=true&key=${API_KEY}&address=${address}&language=es`;

  const formatPlace = (place: Place) => {
    const location: Partial<AppLocation> = {};
    (keys(addressComponentsMapper) as AddressField[]).forEach((component) => {
      const value = parseAddressComponent(place, component);
      set(location, component, value);
    });
    const fullAddress = place.formatted_address;
    const {
      geometry: {
        location: { lat, lng },
      },
    } = place;

    return {
      ...location,
      fullAddress,
      geolocation: { lat, lng },
    } as AppLocation;
  };

  const parseAddressComponent = (place: Place, addressComponent: AddressField) =>
    place.address_components.find((component) => component.types.includes(addressComponentsMapper[addressComponent as string]))?.long_name || '';

  return { options, loading, location, search };
}
