/**
 * Reverse geocoding — turn a tapped coordinate into a real place label.
 *
 * When the user taps the map somewhere with no POI/feature under the finger,
 * we'd otherwise show "Dropped pin" + raw lat/lng. MapMap's `/geocode/reverse`
 * (now live) returns the nearest street/address/postcode, so the place card can
 * name it properly. Only fired on tap (not per keystroke), so the cost is
 * negligible. Never throws — falls back to the dropped pin.
 */
import type { LatLng } from "../../../modules/mapmap-react-native/src/MapmapNav.types";

const API_HOST = "https://api.mapmap.ai";

type ReverseProps = {
  name?: string;
  street?: string;
  housenumber?: string;
  city?: string;
  postcode?: string;
  county?: string;
  state?: string;
  type?: string;
};

/** Prefer a street/address/POI hit over a bare postcode/locality when naming. */
const PREFERRED_TYPES = ["address", "street", "poi"];

function labelFrom(props: ReverseProps): { name: string; address: string } | null {
  const name =
    props.name ??
    (props.housenumber && props.street ? `${props.housenumber} ${props.street}` : props.street) ??
    props.city;
  if (!name) return null;
  const parts = [
    props.street && props.street !== name ? props.street : undefined,
    props.city,
    props.postcode && props.postcode !== name ? props.postcode : undefined,
    props.state,
  ].filter((p): p is string => Boolean(p));
  // De-duplicate while preserving order (city can repeat a county, etc.).
  const address = [...new Set(parts)].join(", ");
  return { name, address };
}

export async function reverseGeocode(
  apiKey: string,
  position: LatLng,
  fetchImpl: typeof fetch = fetch
): Promise<{ name: string; address: string } | null> {
  if (!apiKey) return null;
  try {
    const url =
      `${API_HOST}/geocode/reverse?lon=${position.longitude}&lat=${position.latitude}` +
      `&kinds=address,street,poi,postcode,locality&api_key=${apiKey}`;
    const res = await fetchImpl(url);
    if (!res.ok) return null;
    const body = (await res.json()) as { features?: Array<{ properties?: ReverseProps }> };
    const features = body.features ?? [];
    if (features.length === 0) return null;
    const best =
      features.find((f) => f.properties?.type && PREFERRED_TYPES.includes(f.properties.type)) ??
      features[0];
    return labelFrom(best.properties ?? {});
  } catch {
    return null;
  }
}
