/**
 * MapProvider — the contract every map adapter implements. The host frontend
 * talks to maps only through this interface, so swapping Leaflet for Google or
 * Mapbox later is a new adapter, not a rewrite of the widgets.
 *
 * Adapters receive a DOM element + options and manage their own SDK lifecycle.
 * Infobox content is supplied as a DOM node (rendered by React in the widget),
 * so the popup looks exactly like the chosen infobox design.
 *
 * Methods (all optional to override except init/setMarkers/destroy):
 *   init()                              — create the map instance
 *   setMarkers(records, { onMarkerClick }) — replace all markers
 *   openPopupAt(record, domNode)         — open a popup anchored to a record
 *   closePopup()
 *   panTo(record, zoom?)                 — recentre on a record
 *   fitToMarkers()                      — zoom to show all current markers
 *   drawRadius(center, meters)          — draw/replace the search-radius circle
 *   showDirections(origin, dest)        — draw an in-house route origin→dest
 *   clearDirections()                   — remove any drawn route
 *   destroy()                           — tear down
 */
export class MapProvider {
	constructor( el, opts = {} ) {
		this.el = el;
		this.opts = opts;
	}

	/*
	 * Record accessors — resolved from opts so the framework stays domain-agnostic.
	 * A host whose records aren't shaped like the defaults passes its own
	 * getLatLng / getMarker / getId / getTitle. Defaults match the common
	 * { location|locations[], marker, id, name } shape.
	 */
	latLngOf( record ) {
		return ( this.opts.getLatLng || defaultLatLng )( record );
	}
	markerOf( record ) {
		return ( this.opts.getMarker || defaultMarker )( record );
	}
	idOf( record ) {
		return this.opts.getId ? this.opts.getId( record ) : record?.id;
	}
	titleOf( record ) {
		return this.opts.getTitle ? this.opts.getTitle( record ) : record?.name || '';
	}

	/*
	 * Build a CSS class from the host's prefix (default 'cliq-ui'). Lets a consumer
	 * keep its own class namespace (e.g. 'cliq-sl') so its stylesheet matches the
	 * markup the adapter emits, without the framework hardcoding any consumer name.
	 */
	classFor( name ) {
		return `${ this.opts.classPrefix || 'cliq-ui' }-${ name }`;
	}

	/* eslint-disable no-empty-function, no-unused-vars */
	init() {}
	setMarkers( records, handlers = {} ) {}
	openPopupAt( record, domNode ) {}
	closePopup() {}
	panTo( record, zoom ) {}
	fitToMarkers() {}
	drawRadius( center, meters ) {}
	// Draw a route from origin {lat,lng} to dest {lat,lng} on the map. Returns a
	// Promise<boolean> — false when the adapter can't route (caller may fall back
	// to the external link). Default: not supported.
	showDirections( origin, dest ) { return Promise.resolve( false ); }
	clearDirections() {}
	/* eslint-enable no-empty-function, no-unused-vars */
}

/** Default {lat,lng} accessor — reads a record's primary location. */
export const defaultLatLng = ( record ) => {
	const loc = record?.location || ( Array.isArray( record?.locations ) ? record.locations[ 0 ] : null );
	if ( ! loc ) return null;
	const lat = parseFloat( loc.latitude );
	const lng = parseFloat( loc.longitude );
	if ( Number.isNaN( lat ) || Number.isNaN( lng ) ) return null;
	return { lat, lng };
};

/** Default marker accessor — reads a record's custom marker descriptor. */
export const defaultMarker = ( record ) => record?.marker || null;

/** @deprecated kept for back-compat; prefer the provider's latLngOf(). */
export const recordLatLng = defaultLatLng;
