import Foundation
import UIKit
import CoreLocation
import BaiduMapAPI_Map
import ObjectiveC

extension MapViewImpl {
    private static let polylineColorKey = UnsafeRawPointer(bitPattern: 1001)!
    private static let polylineWidthKey = UnsafeRawPointer(bitPattern: 1002)!
    private static let polylineDottedLineKey = UnsafeRawPointer(bitPattern: 1003)!
    private static let polylineTextureImageKey = UnsafeRawPointer(bitPattern: 1004)!
    private static let polylineTextureKeepScaleKey = UnsafeRawPointer(bitPattern: 1005)!

    @objc public func clearPolylines() {
        for (_, polyline) in self.polylineOverlays {
            self.mapView.remove(polyline)
        }
        self.polylineOverlays.removeAll()
    }

    @objc public func addPolyline(
        _ latitudes: [NSNumber],
        _ longitudes: [NSNumber],
        _ color: String,
        _ width: Double,
        _ dottedLine: Bool
    ) -> Int {
        let count = min(latitudes.count, longitudes.count)
        if count < 2 {
            return -1
        }

        var coordinates: [CLLocationCoordinate2D] = []
        coordinates.reserveCapacity(count)

        for index in 0..<count {
            let latitude = latitudes[index].doubleValue
            let longitude = longitudes[index].doubleValue
            coordinates.append(CLLocationCoordinate2D(latitude: latitude, longitude: longitude))
        }

        let polyline = BMKPolyline(coordinates: &coordinates, count: UInt(count))
        if let polylineValue = polyline {
            let overlayId = self.nextOverlayId
            self.nextOverlayId += 1
            NSLog("addPolyline overlayId=%d count=%d", overlayId, count)

            objc_setAssociatedObject(polylineValue, MapViewImpl.polylineColorKey, color, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            objc_setAssociatedObject(polylineValue, MapViewImpl.polylineWidthKey, NSNumber(value: width), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            objc_setAssociatedObject(polylineValue, MapViewImpl.polylineDottedLineKey, NSNumber(value: dottedLine), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

            self.mapView.add(polylineValue)
            self.polylineOverlays[overlayId] = polylineValue
            return overlayId
        }
        return -1
    }
    
    @objc public func updatePolylineStyle(
        _ overlayId: Int,
        _ latitudes: [NSNumber],
        _ longitudes: [NSNumber],
        _ color: String,
        _ width: Double
    ) {
        guard let polylineValue = self.polylineOverlays[overlayId] else {
            return
        }

        objc_setAssociatedObject(polylineValue, MapViewImpl.polylineColorKey, color, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        objc_setAssociatedObject(polylineValue, MapViewImpl.polylineWidthKey, NSNumber(value: width), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        
        let count = min(latitudes.count, longitudes.count)
        NSLog("addPolyline count=%d", count)
        if count < 2 {
            return
        }
        
        var coordinates: [CLLocationCoordinate2D] = []
        coordinates.reserveCapacity(count)

        for index in 0..<count {
            let latitude = latitudes[index].doubleValue
            let longitude = longitudes[index].doubleValue
            coordinates.append(CLLocationCoordinate2D(latitude: latitude, longitude: longitude))
        }
        polylineValue.setPolylineWithCoordinates(&coordinates, count: UInt(count))

        if let polylineView = self.mapView.view(for: polylineValue) as? BMKPolylineView {
            polylineView.strokeColor = self.colorFromString(color, UIColor.systemBlue)
            polylineView.lineWidth = CGFloat(width)
        }
    }

    @objc public func setPolylineTexture(_ overlayId: Int, _ texturePath: String, _ keepScale: Bool) {
        guard let polylineValue = self.polylineOverlays[overlayId] else {
            return
        }
        guard let image = self.loadImage(texturePath) else {
            NSLog("setPolylineTexture failed: \(texturePath)")
            return
        }

        objc_setAssociatedObject(polylineValue, MapViewImpl.polylineTextureImageKey, image, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        objc_setAssociatedObject(polylineValue, MapViewImpl.polylineTextureKeepScaleKey, NSNumber(value: keepScale), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

        if let polylineView = self.mapView.view(for: polylineValue) as? BMKPolylineView {
            polylineView.textureImage = image
        }
    }

    @objc public func applyPolylineStyle(_ polyline: BMKPolyline, _ polylineView: BMKPolylineView) {
        let color = (objc_getAssociatedObject(polyline, MapViewImpl.polylineColorKey) as? String) ?? "#2F7BFF"
        let width = (objc_getAssociatedObject(polyline, MapViewImpl.polylineWidthKey) as? NSNumber)?.doubleValue ?? 8
        let dottedLine = (objc_getAssociatedObject(polyline, MapViewImpl.polylineDottedLineKey) as? NSNumber)?.boolValue ?? false

        polylineView.strokeColor = self.colorFromString(color, UIColor.systemBlue)
        polylineView.lineWidth = CGFloat(width)
        polylineView.isClickable = true

        if dottedLine {
            polylineView.lineDashType = kBMKLineDashTypeDot
        }
        if let textureImage = objc_getAssociatedObject(polyline, MapViewImpl.polylineTextureImageKey) as? UIImage {
            polylineView.textureImage = textureImage
        }
    }

    @objc public func removePolyline(_ overlayId: Int) {
        guard let polylineValue = self.polylineOverlays[overlayId] else {
            return
        }
        self.mapView.remove(polylineValue)
        self.polylineOverlays.removeValue(forKey: overlayId)
    }
}
