//
//  LocationGeocoder.swift
//  suixinkan
//

import CoreLocation
import Foundation

/// 地址逆地理编码能力，供平台定位实现注入。
@MainActor
protocol LocationAddressGeocoding: AnyObject {
    /// 将坐标解析为可读地址，失败时返回空字符串。
    func reverseGeocode(latitude: Double, longitude: Double) async -> String
}

/// 平台逆地理编码封装；真机使用高德，模拟器使用 Core Location。
@MainActor
final class LocationGeocoder: NSObject, LocationAddressGeocoding {

    nonisolated static let shared = LocationGeocoder()

    #if targetEnvironment(simulator)
    private let geocoder = CLGeocoder()
    #else
    private var searchAPI: AMapSearchAPI?
    private var continuation: CheckedContinuation<String, Never>?
    #endif

    nonisolated private override init() {
        super.init()
    }

    /// 将坐标解析为可读地址。
    func reverseGeocode(latitude: Double, longitude: Double) async -> String {
        #if targetEnvironment(simulator)
        let location = CLLocation(latitude: latitude, longitude: longitude)
        guard let placemark = try? await geocoder.reverseGeocodeLocation(location).first else {
            return ""
        }
        if let name = placemark.name?.trimmingCharacters(in: .whitespacesAndNewlines),
           !name.isEmpty {
            return name
        }
        return [
            placemark.administrativeArea,
            placemark.locality,
            placemark.subLocality,
            placemark.thoroughfare,
            placemark.subThoroughfare,
        ]
        .compactMap { $0?.trimmingCharacters(in: .whitespacesAndNewlines) }
        .filter { !$0.isEmpty }
        .joined()
        #else
        do {
            try AMapBootstrap.requireConfigured()
        } catch {
            return ""
        }

        return await withCheckedContinuation { continuation in
            self.continuation?.resume(returning: "")
            self.continuation = continuation

            guard let api = makeSearchAPI() else {
                continuation.resume(returning: "")
                return
            }
            let request = AMapReGeocodeSearchRequest()
            request.location = AMapGeoPoint.location(withLatitude: CGFloat(latitude), longitude: CGFloat(longitude))
            request.requireExtension = true
            request.radius = 200
            api.aMapReGoecodeSearch(request)
        }
        #endif
    }

    #if !targetEnvironment(simulator)
    func onReGeocodeSearchDone(_ request: AMapReGeocodeSearchRequest!, response: AMapReGeocodeSearchResponse!) {
        let address = response?.regeocode?.formattedAddress ?? ""
        continuation?.resume(returning: address)
        continuation = nil
    }

    func aMapSearchRequest(_ request: Any!, didFailWithError error: Error!) {
        continuation?.resume(returning: "")
        continuation = nil
    }

    private func makeSearchAPI() -> AMapSearchAPI? {
        if let searchAPI {
            return searchAPI
        }
        guard let api = AMapSearchAPI() else { return nil }
        api.delegate = self
        searchAPI = api
        return api
    }
    #endif
}

#if !targetEnvironment(simulator)
extension LocationGeocoder: AMapSearchDelegate {}
#endif
