//
//  LocationService.swift
//  ylgamehall
//
//  高德 AMapLocationManager 异步包装：一次性 / 持续两种模式。
//  契约 §3.2 ［6］ getlocationinfo 9 字段；msext gameController.m:2491-2557 等价。
//
//  ⚠️ canImport(AMapLocationKit) 守卫：SDK 未链接时 LocationService 永远抛
//  LocationError.sdkNotLinked，handler 兜底退化为 stub 行为。
//

import Foundation
import CoreLocation

#if canImport(AMapLocationKit)
import AMapLocationKit
#endif
#if canImport(AMapFoundationKit)
import AMapFoundationKit
#endif

/// 9 字段定位结果。字段名严格 1:1 H5 端契约（contract §3.2 表 [6]）：
///   - latitude / longitude **是 string** (`String(format: "%f", ...)`)
///   - province **小写 p**（与 sharelogin.Province 大写不同）
public struct LocationPayload: Sendable {
    public let address:   String
    public let city:      String
    public let cityCode:  String
    public let country:   String
    public let district:  String
    public let latitude:  String
    public let longitude: String
    public let province:  String
    public let street:    String
}

public enum LocationError: Error, Sendable {
    case sdkNotLinked
    case authorizationDenied
    case timeout
    case underlying(any Error)
}

@MainActor
public final class LocationService {

    public static let shared = LocationService()

    public init() {}

    #if canImport(AMapLocationKit)
    private let manager: AMapLocationManager = {
        let m = AMapLocationManager()
        m.desiredAccuracy = kCLLocationAccuracyHundredMeters
        m.locationTimeout = 6
        m.reGeocodeTimeout = 3
        m.locatingWithReGeocode = true
        return m
    }()
    #endif

    /// 一次性定位 + 逆地理（msext locAction + completionBlock 等价）
    public func requestOnce() async throws -> LocationPayload {
        #if canImport(AMapLocationKit)
        return try await withCheckedThrowingContinuation { (cont: CheckedContinuation<LocationPayload, Error>) in
            manager.requestLocation(withReGeocode: true) { loc, regeo, err in
                if let err = err as NSError? {
                    // msext 行为：权限相关错误归一到 12 errorCode（handler 转字段）
                    if err.code == AMapLocationErrorCode.locateFailed.rawValue {
                        cont.resume(throwing: LocationError.authorizationDenied)
                    } else {
                        cont.resume(throwing: LocationError.underlying(err))
                    }
                    return
                }
                guard let loc, let regeo else {
                    cont.resume(throwing: LocationError.timeout)
                    return
                }
                cont.resume(returning: LocationPayload(
                    address:   regeo.formattedAddress ?? "",
                    city:      regeo.city             ?? "",
                    cityCode:  regeo.citycode         ?? "",
                    country:   regeo.country          ?? "",
                    district:  regeo.district         ?? "",
                    latitude:  String(format: "%f", loc.coordinate.latitude),
                    longitude: String(format: "%f", loc.coordinate.longitude),
                    province:  regeo.province         ?? "",
                    street:    regeo.street           ?? ""
                ))
            }
        }
        #else
        throw LocationError.sdkNotLinked
        #endif
    }

    /// 停止：msext gameController.m:2473-2478 cleanUpAction 等价
    public func stop() {
        #if canImport(AMapLocationKit)
        manager.stopUpdatingLocation()
        manager.delegate = nil
        #endif
    }
}
