# Copyright 2026, Jiri Eischmann <jiri@eischmann.cz> and the meshy contributors
# SPDX-License-Identifier: GPL-3.0-or-later

"""CoreLocation-based location service for macOS."""

import logging

log = logging.getLogger(__name__)

try:
    from Foundation import NSObject
    from CoreLocation import (
        CLLocationManager,
        kCLAuthorizationStatusAuthorizedAlways,
        kCLAuthorizationStatusAuthorizedWhenInUse,
        kCLAuthorizationStatusDenied,
        kCLAuthorizationStatusNotDetermined,
        kCLAuthorizationStatusRestricted,
    )
    CORELOCATION_AVAILABLE = True
except ImportError:
    log.warning("CoreLocation not available")
    CORELOCATION_AVAILABLE = False
    NSObject = object


class LocationDelegate(NSObject):
    """Delegate for CoreLocation manager."""

    def init(self):
        """Initialize the delegate."""
        from objc import super as objc_super
        self = objc_super(LocationDelegate, self).init()
        if self is None:
            return None

        self._callback = None
        self._manager = None
        return self

    def setCallback_(self, callback):
        """Set the callback to call with location results."""
        self._callback = callback

    def setManager_(self, manager):
        """Set the location manager."""
        self._manager = manager

    def locationManager_didUpdateLocations_(self, manager, locations):
        """Called when location is updated."""
        if not locations or not self._callback:
            return

        location = locations[-1]  # Most recent location
        coordinate = location.coordinate()

        log.info(f"Location updated: {coordinate.latitude}, {coordinate.longitude}")

        # Call callback on main thread
        from gi.repository import GLib
        GLib.idle_add(
            lambda: self._callback(coordinate.latitude, coordinate.longitude, None)
            if self._callback else None
        )

        # Stop updating after getting one location
        if self._manager:
            self._manager.stopUpdatingLocation()

    def locationManager_didFailWithError_(self, manager, error):
        """Called when location update fails."""
        log.error(f"Location error: {error}")

        # Call callback with error on main thread
        from gi.repository import GLib
        GLib.idle_add(
            lambda: self._callback(None, None, str(error))
            if self._callback else None
        )

    def locationManager_didChangeAuthorizationStatus_(self, manager, status):
        """Called when authorization status changes."""
        if status == kCLAuthorizationStatusAuthorizedWhenInUse:
            log.info("Location permission granted (when in use)")
            manager.requestLocation()
        elif status == kCLAuthorizationStatusAuthorizedAlways:
            log.info("Location permission granted (always)")
            manager.requestLocation()
        elif status == kCLAuthorizationStatusDenied:
            log.warning("Location permission denied")
            if self._callback:
                from gi.repository import GLib
                GLib.idle_add(
                    lambda: self._callback(None, None, "Location permission denied")
                )
        elif status == kCLAuthorizationStatusRestricted:
            log.warning("Location permission restricted")
            if self._callback:
                from gi.repository import GLib
                GLib.idle_add(
                    lambda: self._callback(None, None, "Location permission restricted")
                )


def get_location_macos(callback):
    """Get current location using CoreLocation.

    Args:
        callback: Function to call with (latitude, longitude, error).
                  If successful, error is None. If failed, lat/lon are None.
    """
    if not CORELOCATION_AVAILABLE:
        from gi.repository import GLib
        GLib.idle_add(lambda: callback(None, None, "CoreLocation not available"))
        return

    try:
        # Create location manager and delegate on main thread
        from gi.repository import GLib

        def _init_location():
            manager = CLLocationManager.alloc().init()
            delegate = LocationDelegate.alloc().init()

            delegate.setCallback_(callback)
            delegate.setManager_(manager)
            manager.setDelegate_(delegate)

            # Request permission
            auth_status = CLLocationManager.authorizationStatus()

            if auth_status == kCLAuthorizationStatusNotDetermined:
                log.info("Requesting location permission")
                manager.requestWhenInUseAuthorization()
            elif auth_status in (kCLAuthorizationStatusAuthorizedWhenInUse,
                                 kCLAuthorizationStatusAuthorizedAlways):
                log.info("Location already authorized, requesting location")
                manager.requestLocation()
            elif auth_status == kCLAuthorizationStatusDenied:
                callback(None, None, "Location permission denied")
            elif auth_status == kCLAuthorizationStatusRestricted:
                callback(None, None, "Location permission restricted")

            return False  # Don't repeat

        GLib.idle_add(_init_location)

    except Exception as e:
        log.error(f"Failed to get location: {e}")
        from gi.repository import GLib
        GLib.idle_add(lambda: callback(None, None, str(e)))
