/**
 * GeoLocationService — Reusable browser geolocation + reverse geocoding.
 *
 * Uses navigator.geolocation and OpenStreetMap Nominatim (free, no API key).
 * All methods return Promises. ES5 compatible (no async/await).
 *
 * API:
 *   GeoLocationService.getCurrentPosition()  → Promise<{ lat, lon }>
 *   GeoLocationService.reverseGeocode(lat, lon) → Promise<{ address, suburb, city, state, postcode, country }>
 *   GeoLocationService.getLocalArea()         → Promise<{ lat, lon, address, suburb, city, state, postcode, country, displayName }>
 *   GeoLocationService.parseAddress(nominatimResult) → { address, suburb, city, state, postcode, country, displayName }
 */
var GeoLocationService = (function () {

    var NOMINATIM_URL = 'https://nominatim.openstreetmap.org/reverse';

    /**
     * Get the user's current coordinates via browser geolocation.
     * Returns Promise<{ lat, lon }>
     */
    function getCurrentPosition() {
        return new Promise(function (resolve, reject) {
            if (!navigator.geolocation) {
                reject(new Error('Geolocation is not supported by this browser.'));
                return;
            }
            navigator.geolocation.getCurrentPosition(
                function (position) {
                    resolve({
                        lat: position.coords.latitude,
                        lon: position.coords.longitude,
                    });
                },
                function (error) {
                    var messages = {
                        1: 'Location permission denied.',
                        2: 'Location unavailable.',
                        3: 'Location request timed out.',
                    };
                    reject(new Error(messages[error.code] || 'Unknown geolocation error.'));
                },
                { enableHighAccuracy: false, timeout: 10000, maximumAge: 300000 }
            );
        });
    }

    /**
     * Parse a Nominatim result (reverse or forward search) into a normalised
     * { address, suburb, city, state, postcode, country, displayName } shape.
     * Shared by reverseGeocode() and any component doing its own Nominatim
     * forward-search parsing (e.g. LocationPicker's manual address search).
     */
    function parseAddress(data) {
        var addr = data.address || {};
        var suburb = addr.suburb || addr.neighbourhood || addr.hamlet || addr.village || '';
        var city = addr.city || addr.town || addr.municipality || '';
        var state = addr.state || '';
        var postcode = addr.postcode || '';
        var country = addr.country || '';

        // Build a concise display name: "Suburb, City" or "City, State"
        var parts = [];
        if (suburb) parts.push(suburb);
        if (city && city !== suburb) parts.push(city);
        if (state && !city) parts.push(state);
        var displayName = parts.join(', ') || data.display_name || '';

        return {
            address: data.display_name || '',
            suburb: suburb,
            city: city,
            state: state,
            postcode: postcode,
            country: country,
            displayName: displayName,
        };
    }

    /**
     * Reverse geocode coordinates via OpenStreetMap Nominatim.
     * Returns Promise<{ address, suburb, city, state, postcode, country }>
     */
    function reverseGeocode(lat, lon) {
        var url = NOMINATIM_URL +
            '?lat=' + encodeURIComponent(lat) +
            '&lon=' + encodeURIComponent(lon) +
            '&format=json&addressdetails=1&zoom=16';

        return fetch(url, {
            headers: { 'Accept': 'application/json' },
        })
        .then(function (res) {
            if (!res.ok) throw new Error('Geocoding request failed: ' + res.status);
            return res.json();
        })
        .then(function (data) {
            return parseAddress(data);
        });
    }

    /**
     * Convenience: get position then reverse geocode in one call.
     * Returns Promise<{ lat, lon, address, suburb, city, state, postcode, country, displayName }>
     */
    function getLocalArea() {
        return getCurrentPosition().then(function (coords) {
            return reverseGeocode(coords.lat, coords.lon).then(function (geo) {
                geo.lat = coords.lat;
                geo.lon = coords.lon;
                return geo;
            });
        });
    }

    return {
        getCurrentPosition: getCurrentPosition,
        reverseGeocode: reverseGeocode,
        getLocalArea: getLocalArea,
        parseAddress: parseAddress,
    };
})();

window.GeoLocationService = GeoLocationService;
