// SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
//
// SPDX-License-Identifier: Apache-2.0

import type { LocationDto } from '@citrineos/base';

export interface GeocodingResult {
  address_components: AddressComponent[];
  formatted_address: string;
  geometry: Geometry;
  place_id: string;
  types: string[];
}

export interface AddressComponent {
  long_name: string;
  short_name: string;
  types: string[];
}

export interface Geometry {
  location: LatLng;
  location_type: string;
  viewport: Viewport;
}

export interface LatLng {
  lat: number;
  lng: number;
}

export interface Viewport {
  northeast: LatLng;
  southwest: LatLng;
}

/**
 * Geocode an address using OpenStreetMap Nominatim API (free, no API key required)
 */
export const geocodeAddress = async (address: string): Promise<GeocodingResult> => {
  const encodedAddress = encodeURIComponent(address);
  const geocodeUrl = `https://nominatim.openstreetmap.org/search?format=json&q=${encodedAddress}&limit=1`;

  try {
    const response = await fetch(geocodeUrl, {
      headers: {
        'User-Agent': 'CitrineOS-Operator-UI/1.0',
      },
    });
    const data = await response.json();

    if (data && data.length > 0) {
      const result = data[0];
      return {
        address_components: [],
        formatted_address: result.display_name || '',
        geometry: {
          location: {
            lat: parseFloat(result.lat),
            lng: parseFloat(result.lon),
          },
          location_type: 'APPROXIMATE',
          viewport: {
            northeast: {
              lat: parseFloat(result.boundingbox?.[0] || result.lat),
              lng: parseFloat(result.boundingbox?.[2] || result.lon),
            },
            southwest: {
              lat: parseFloat(result.boundingbox?.[1] || result.lat),
              lng: parseFloat(result.boundingbox?.[3] || result.lon),
            },
          },
        },
        place_id: result.place_id?.toString() || '',
        types: result.type ? [result.type] : [],
      };
    } else {
      console.error('No coordinates found for this address.', data);
      return Promise.reject('No coordinates found for this address.');
    }
  } catch (error: any) {
    console.error('Geocoding error:', error);
    return Promise.reject('No coordinates found for this address. Error: ' + error.message);
  }
};

export const getAddressComponent = (components: AddressComponent[], type: string): string => {
  const found = components.find((comp) => comp.types.includes(type));
  return found ? found.long_name : '';
};

export const getFullAddress = (location: Partial<LocationDto>) => {
  return `${location.address || ''}, ${location.city || ''}, ${
    location.state || ''
  } ${location.postalCode || ''}, ${location.country || ''}`.trim();
};
