import Foundation
import CoreLocation

/// Thin wrapper around CLLocationManager exposing an async one-shot fix
/// API. We only need "where is the user right now so I can center the
/// map" — not continuous tracking, not background updates. The Live tab
/// calls `requestOneShotLocation()` once on appear and is done.
///
/// Permission state is published so the view can decide between
/// (a) centering on the user, (b) restoring last viewed region, or
/// (c) showing a continental fallback.
@MainActor
final class LocationService: NSObject, ObservableObject {
    static let shared = LocationService()

    @Published private(set) var authorization: CLAuthorizationStatus
    @Published private(set) var lastKnown: CLLocationCoordinate2D?

    private let manager = CLLocationManager()
    private var pendingContinuations: [CheckedContinuation<CLLocationCoordinate2D?, Never>] = []

    private override init() {
        self.authorization = manager.authorizationStatus
        super.init()
        manager.delegate = self
        manager.desiredAccuracy = kCLLocationAccuracyHundredMeters
    }

    /// Ask the OS for permission (if needed) and return the next location
    /// fix, or nil if the user denied access. Resolves once — does not
    /// stay subscribed.
    func requestOneShotLocation() async -> CLLocationCoordinate2D? {
        switch authorization {
        case .denied, .restricted:
            return nil
        case .notDetermined:
            manager.requestWhenInUseAuthorization()
            // Fall through to request location after the delegate flips
            // auth — we capture the continuation now and resume it once
            // location/auth-denied lands.
        default:
            break
        }
        return await withCheckedContinuation { cont in
            pendingContinuations.append(cont)
            // requestLocation is a one-shot; safe to call before auth has
            // been granted — CL will queue it and fire after grant.
            manager.requestLocation()
        }
    }

    private func resumeAll(with value: CLLocationCoordinate2D?) {
        let waiters = pendingContinuations
        pendingContinuations.removeAll()
        for c in waiters { c.resume(returning: value) }
    }
}

extension LocationService: CLLocationManagerDelegate {
    nonisolated func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        Task { @MainActor in
            self.authorization = manager.authorizationStatus
            if manager.authorizationStatus == .denied || manager.authorizationStatus == .restricted {
                self.resumeAll(with: nil)
            }
        }
    }

    nonisolated func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let loc = locations.last else { return }
        Task { @MainActor in
            self.lastKnown = loc.coordinate
            self.resumeAll(with: loc.coordinate)
        }
    }

    nonisolated func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        Task { @MainActor in
            self.resumeAll(with: nil)
        }
    }
}
