//
//  MapAmapGeneralProcessing.swift
//  map_amap_ios
//
//  Created by 诺诺诺的言 on 2025/7/22.
//

import Foundation
import MapKit
import ObjectiveC

extension Decodable {
    static func fromJson(json: Any) -> Self? {
        do {
            let data = try JSONSerialization.data(withJSONObject: json, options: [])
            return try JSONDecoder().decode(Self.self, from: data)
        } catch {
            print(error.localizedDescription)
            return nil
        }
    }
}

extension Encodable {
    func toJson() -> [String: Any] {
        guard let data = try? JSONEncoder().encode(self) else {
            return [:]
        }
        return try! JSONSerialization.jsonObject(with: data, options: []) as! [String: Any]
    }
}

struct ATMapCameraPosition: Codable {
    var latitude: CGFloat
    var longitude: CGFloat
    // 地图缩放比例，对应span
    var zoom: CGFloat
}

struct ATMapPadding: Codable {
    var top: CGFloat
    var left: CGFloat
    var bottom: CGFloat
    var right: CGFloat

    var padding: UIEdgeInsets {
        return UIEdgeInsets(top: top, left: left, bottom: bottom, right: right)
    }
}


// 定义关联对象的键
private var associatedLineIdKey = "associatedLineIdKey"
private var associatedLineTypeKey = "associatedLineTypeKey"
private var associatedColorKey = "associatedColorKey"
private var associatedWidthKey = "associatedWidthKey"

extension MKPolyline {
    // 关联 lineId 属性
    var associatedLineId: String? {
        get {
            return objc_getAssociatedObject(self, &associatedLineIdKey) as? String
        }
        set {
            objc_setAssociatedObject(self, &associatedLineIdKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    // 关联 lineType 属性
    var associatedLineType: String? {
        get {
            return objc_getAssociatedObject(self, &associatedLineTypeKey) as? String
        }
        set {
            objc_setAssociatedObject(self, &associatedLineTypeKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    // 关联 color 属性
    var associatedColor: String? {
        get {
            return objc_getAssociatedObject(self, &associatedColorKey) as? String
        }
        set {
            objc_setAssociatedObject(self, &associatedColorKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    // 关联 width 属性
    var associatedWidth: Double? {
        get {
            return objc_getAssociatedObject(self, &associatedWidthKey) as? Double
        }
        set {
            objc_setAssociatedObject(self, &associatedWidthKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}


class ATMapPolyline: NSObject, Codable {
    var id: String = UUID().uuidString
    var lineId: String         // 新增：用于记录的线ID
    var lineType: String      // 新增：用于记录线的样式 normal error selected color
    var points: [CLLocationCoordinate2D]
    var mapPadding: ATMapPadding?
    var color : String ///轨迹的颜色
    var width: Double /// 轨迹的宽度
    
    var polyline: MKPolyline {
        return MKPolyline(coordinates: points, count: points.count)
    }

    enum CodingKeys: String, CodingKey {
        case lineId, lineType, points, mapPadding,color,width
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        if container.contains(.lineId) {
            lineId = try container.decodeIfPresent(String.self, forKey: .lineId) ?? ""
        } else {
            lineId = ""
        }
        if container.contains(.lineType) {
            lineType = try container.decodeIfPresent(String.self, forKey: .lineType) ?? ""
        } else {
            lineType = "";
        }
        if container.contains(.points) {
            points = try container.decodeIfPresent([CLLocationCoordinate2D].self, forKey: .points) ?? [CLLocationCoordinate2D]()
        } else {
            points = [CLLocationCoordinate2D]()
        }
        if container.contains(.color) {
            color = try container.decodeIfPresent(String.self, forKey: .color) ?? ""
        } else {
            color = ""
        }
        if container.contains(.width) {
            width = try container.decodeIfPresent(Double.self, forKey: .width) ?? 0
        } else {
            width = 0
        }
        if container.contains(.mapPadding) {
            mapPadding = try container.decodeIfPresent(ATMapPadding.self, forKey: .mapPadding) ?? ATMapPadding(top: 0, left: 0, bottom: 0, right: 0)
        } else {
            mapPadding = ATMapPadding(top: 0, left: 0, bottom: 0, right: 0)
        }
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(lineId, forKey: .lineId)
        try container.encode(lineType, forKey: .lineType)
        try container.encode(points, forKey: .points)
        try container.encodeIfPresent(mapPadding, forKey: .mapPadding)
    }
    
    // 初始化方法
    init(lineId: String, lineType: String, points: [CLLocationCoordinate2D], mapPadding: ATMapPadding? = nil,color : String,width : Double) {
        self.lineId = lineId
        self.lineType = lineType
        self.points = points
        self.mapPadding = mapPadding
        self.color = color
        self.width = width
        super.init()
    }
}


class ATMapMarker: NSObject, Codable {
    var id: String
    var markerId: String
    var markerName: String?
    var customAvatarUrl : String?
    var latitude: CGFloat
    var longitude: CGFloat
    var isSelected: Bool
    var markerType: any MapMarkerSupportType
    var tags: [String : String]?

    init(id: String, markerId: String,markerName: String?, customAvatarUrl: String?,location: CLLocationCoordinate2D, markerType: any MapMarkerSupportType, isSelected: Bool = false,tags: [String : String]?) {
        self.id = id
        self.markerId = markerId
        self.markerName = markerName
        self.customAvatarUrl = customAvatarUrl
        self.latitude = location.latitude
        self.longitude = location.longitude
        self.markerType = markerType
        self.isSelected = isSelected
        self.tags = tags
    }
    
    func update(coordinate: CLLocationCoordinate2D, name: String? = nil, isSelect: Bool) {
        self.latitude = coordinate.latitude
        self.longitude = coordinate.longitude
        self.markerName = name
        self.isSelected = isSelect
    }

    enum CodingKeys: String, CodingKey {
        case id,markerId,markerName,customAvatarUrl, latitude, longitude, isSelected, markerType,tags
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(String.self, forKey: .id)
        if id.isEmpty {
            id = "user_location"
        }
        if container.contains(.markerName) {
            markerName = try container.decodeIfPresent(String.self, forKey: .markerName) ?? ""
        } else {
            markerName = ""
        }
        if container.contains(.customAvatarUrl) {
            customAvatarUrl = try container.decodeIfPresent(String.self, forKey: .customAvatarUrl) ?? ""
        } else {
            customAvatarUrl = ""
        }
        
        if container.contains(.latitude) {
            latitude = try container.decodeIfPresent(CGFloat.self, forKey: .latitude) ?? 0
        } else {
            latitude = 0
        }
        if container.contains(.longitude) {
            longitude = try container.decodeIfPresent(CGFloat.self, forKey: .longitude) ?? 0
        } else {
            longitude = 0
        }
        if container.contains(.isSelected) {
            isSelected = try container.decodeIfPresent(Bool.self, forKey: .isSelected) ?? false
        } else {
            isSelected = false
        }
   
        
        // 使用工厂方法创建正确类型的markerType
        if container.contains(.markerType) {
            let rawValue = try container.decodeIfPresent(Int.self, forKey: .markerType) ?? 1
            markerType = MarkerTypeFactory.markerType(from: rawValue)
        } else {
            markerType = MarkerTypeFactory.markerType(from: 1)
        }
        
        ///气泡内容
        // 处理tags为空的情况
         if container.contains(.tags) {
             tags = try container.decodeIfPresent([String: String].self, forKey: .tags) ?? [:]
         } else {
             tags = [:] // 默认为空字典
         }
        if container.contains(.markerId) {
            markerId = try container.decodeIfPresent(String.self, forKey: .markerId) ?? ""
        } else {
            markerId = ""
        }
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(markerName, forKey: .markerName)
        try container.encode(customAvatarUrl, forKey: .customAvatarUrl)
        try container.encode(latitude, forKey: .latitude)
        try container.encode(longitude, forKey: .longitude)
        try container.encode(isSelected, forKey: .isSelected)
        try container.encode(markerType.rawValue, forKey: .markerType)
        try container.encode(tags, forKey: .tags)
        try container.encode(markerId, forKey: .markerId)
    }
}

extension ATMapMarker: MKAnnotation {
    var coordinate: CLLocationCoordinate2D {
        return CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
    }
}

extension CLLocationCoordinate2D: Codable {
    enum CodingKeys: String, CodingKey {
        case latitude
        case longitude
    }
    
    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let latitude = try container.decode(Double.self, forKey: .latitude)
        let longitude = try container.decode(Double.self, forKey: .longitude)
        self.init(latitude: latitude, longitude: longitude)
    }
    
    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(latitude, forKey: .latitude)
        try container.encode(longitude, forKey: .longitude)
    }
}


class ATMapLocation: NSObject, Codable {
    var latitude: CGFloat?
    var longitude: CGFloat?
    var address: String?
    var errorCode: Int = 0
    var time: Int?
    var bearing: CGFloat?
    var speed: CGFloat?

    init(latitude: CGFloat? = nil, longitude: CGFloat? = nil, address: String? = nil, time: Int? = nil, bearing: CGFloat? = nil, speed: CGFloat? = nil) {
        self.latitude = latitude
        self.longitude = longitude
        self.address = address
        self.time = time
        self.bearing = bearing
        self.speed = speed
        super.init()
    }

    static func fromLocation(location: CLLocation) -> ATMapLocation {
        return ATMapLocation(
            latitude: CGFloat(location.coordinate.latitude),
            longitude: CGFloat(location.coordinate.longitude),
            address: nil,
            time: Int(location.timestamp.timeIntervalSince1970 * 1000),
            bearing: CGFloat(location.course),
            speed: CGFloat(location.speed)
        )
    }

}
