//
//  LocationProvider.swift
//  suixinkan
//

import CoreLocation
import Foundation

/// 统一定位服务，封装高德 `AMapLocationManager`，对齐 Android `LocationProvider`。
final class LocationProvider: NSObject, LocationProviding {

    static let shared = LocationProvider()

    private let permissionManager = CLLocationManager()
    private let geocoder: LocationGeocoder

    init(geocoder: LocationGeocoder = .shared) {
        self.geocoder = geocoder
        super.init()
        permissionManager.desiredAccuracy = kCLLocationAccuracyBest
    }

    func requestSnapshot(desiredAccuracy: CLLocationAccuracy = kCLLocationAccuracyBest) async throws -> HomeLocationSnapshot {
        try AMapBootstrap.requireConfigured()
        try await ensureLocationPermission()

        let manager = makeLocationManager(
            desiredAccuracy: desiredAccuracy,
            locatingWithReGeocode: true
        )
        return try await withCheckedThrowingContinuation { continuation in
            let started = manager.requestLocation(withReGeocode: true) { location, regeocode, error in
                if let error {
                    continuation.resume(throwing: error)
                    return
                }
                guard let location else {
                    continuation.resume(throwing: LocationProviderError.locationFailed)
                    return
                }
                let address = regeocode?.formattedAddress ?? ""
                continuation.resume(returning: HomeLocationSnapshot(
                    latitude: location.coordinate.latitude,
                    longitude: location.coordinate.longitude,
                    address: address
                ))
            }
            if !started {
                continuation.resume(throwing: LocationProviderError.locationFailed)
            }
        }
    }

    func requestCoordinate(desiredAccuracy: CLLocationAccuracy) async throws -> CLLocationCoordinate2D {
        try AMapBootstrap.requireConfigured()
        try await ensureLocationPermission()

        let manager = makeLocationManager(
            desiredAccuracy: desiredAccuracy,
            locatingWithReGeocode: false
        )
        return try await withCheckedThrowingContinuation { continuation in
            let started = manager.requestLocation(withReGeocode: false) { location, _, error in
                if let error {
                    continuation.resume(throwing: error)
                    return
                }
                guard let location else {
                    continuation.resume(throwing: LocationProviderError.locationFailed)
                    return
                }
                continuation.resume(returning: location.coordinate)
            }
            if !started {
                continuation.resume(throwing: LocationProviderError.locationFailed)
            }
        }
    }

    func reverseGeocode(latitude: Double, longitude: Double) async -> String {
        await geocoder.reverseGeocode(latitude: latitude, longitude: longitude)
    }

    /// 请求系统定位权限，首次弹窗后等待用户响应。
    func ensureLocationPermission() async throws {
        let initialStatus = permissionManager.authorizationStatus
        if initialStatus == .notDetermined {
            permissionManager.requestWhenInUseAuthorization()
            try await Task.sleep(nanoseconds: 500_000_000)
        }

        let status = permissionManager.authorizationStatus
        guard status == .authorizedWhenInUse || status == .authorizedAlways else {
            throw LocationProviderError.permissionDenied
        }
    }

    private func makeLocationManager(
        desiredAccuracy: CLLocationAccuracy,
        locatingWithReGeocode: Bool
    ) -> AMapLocationManager {
        let manager = AMapLocationManager()
        manager.desiredAccuracy = desiredAccuracy
        manager.locationTimeout = 30
        manager.reGeocodeTimeout = 10
        manager.locatingWithReGeocode = locatingWithReGeocode
        return manager
    }
}
