import axios from 'axios';

const GEOCODING_URL = 'https://maps.googleapis.com/maps/api/geocode/json';

const parseAddressComponents = (components) => {
  const get = (type, nameType = 'long_name') =>
    components.find((c) => c.types.includes(type))?.[nameType] ?? '';

  return {
    address: `${get('route')}`.trim(),
    number: get('street_number'),
    district: get('sublocality_level_1') || get('sublocality') || get('neighborhood'),
    city: get('administrative_area_level_2'),
    state: get('administrative_area_level_1', 'short_name'),
    zip_code: get('postal_code').replace(/\D/g, ''),
  };
};

const geocodeViaGoogleMaps = async (request) => {
  const geocoder = new window.google.maps.Geocoder();
  const { results } = await geocoder.geocode(request);
  return results ?? [];
};

export const useGeocodingApi = () => {
  const geocodeCep = async (cep) => {
    const cleaned = cep.replace(/\D/g, '');
    const apiKey = process.env.GOOGLE_MAPS_API_KEY;
    const usandoGeocoderNativo = !!window.google?.maps?.Geocoder;

    if (usandoGeocoderNativo) {
      const results = await geocodeViaGoogleMaps({ address: `${cleaned}, Brazil` });
      if (!results.length) return null;
      const result = results[0];
      const parsed = parseAddressComponents(result.address_components);
      return {
        lat: result.geometry.location.lat(),
        lng: result.geometry.location.lng(),
        ...parsed,
      };
    }

    const { data } = await axios.get(GEOCODING_URL, {
      params: { address: `${cleaned}, Brazil`, key: apiKey },
    });
    if (data.status !== 'OK' || !data.results.length) return null;
    const result = data.results[0];
    const { lat, lng } = result.geometry.location;
    return { lat, lng, ...parseAddressComponents(result.address_components) };
  };

  const reverseGeocode = async (lat, lng) => {
    const apiKey = process.env.GOOGLE_MAPS_API_KEY;
    const usandoGeocoderNativo = !!window.google?.maps?.Geocoder;

    if (usandoGeocoderNativo) {
      const results = await geocodeViaGoogleMaps({ location: { lat, lng } });
      if (!results.length) return null;
      return { lat, lng, ...parseAddressComponents(results[0].address_components) };
    }

    const { data } = await axios.get(GEOCODING_URL, {
      params: { latlng: `${lat},${lng}`, key: apiKey },
    });
    if (data.status !== 'OK' || !data.results.length) return null;
    const result = data.results[0];
    return { lat, lng, ...parseAddressComponents(result.address_components) };
  };

  const geocodeFullAddress = async ({ address, number, district, zip_code, city, state }) => {
    const parts = [address, number, district, zip_code, city, state, 'Brazil'].filter(Boolean);
    const query = parts.join(', ');
    const apiKey = process.env.GOOGLE_MAPS_API_KEY;
    const usandoGeocoderNativo = !!window.google?.maps?.Geocoder;

    if (usandoGeocoderNativo) {
      const results = await geocodeViaGoogleMaps({ address: query });
      if (!results.length) return null;
      const result = results[0];
      return {
        lat: result.geometry.location.lat(),
        lng: result.geometry.location.lng(),
        ...parseAddressComponents(result.address_components),
      };
    }

    const { data } = await axios.get(GEOCODING_URL, {
      params: { address: query, key: apiKey },
    });
    if (data.status !== 'OK' || !data.results.length) return null;
    const result = data.results[0];
    const { lat, lng } = result.geometry.location;
    return { lat, lng, ...parseAddressComponents(result.address_components) };
  };

  return { geocodeCep, reverseGeocode, geocodeFullAddress };
};
