//
//  Models.swift
//  Runner
//
//  Created by Groot on 2025/5/9.
//

import Foundation
import MapKit

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)
    }
}

// 定义线的类型枚举
enum PolylineType: String, Codable {
    case solid      // 实线
    case dashed     // 虚线
    case dotted     // 点线
    case mixed      // 混合样式
}

class ATMapPolyline: NSObject, Codable {
    var id: String = UUID().uuidString
    var lineId: String              // 新增：用于记录的线ID
    var lineType: PolylineType      // 新增：用于记录线的样式
    var points: [CLLocationCoordinate2D]
    var mapPadding: ATMapPadding?
    
    var polyline: MKPolyline {
        return MKPolyline(coordinates: points, count: points.count)
    }

    enum CodingKeys: String, CodingKey {
        case lineId, lineType, points, mapPadding
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        lineId = try container.decode(String.self, forKey: .lineId)
        lineType = try container.decode(PolylineType.self, forKey: .lineType)
        points = try container.decode([CLLocationCoordinate2D].self, forKey: .points)
        
        if container.contains(.mapPadding) {
            mapPadding = try container.decodeIfPresent(ATMapPadding.self, forKey: .mapPadding)
        }
    }
    
    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: PolylineType, points: [CLLocationCoordinate2D], mapPadding: ATMapPadding? = nil) {
        self.lineId = lineId
        self.lineType = lineType
        self.points = points
        self.mapPadding = mapPadding
        super.init()
    }
}


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

    init(id: String, markerName: String?, customAvatarUrl: String?,location: CLLocationCoordinate2D, markerType: any MapMarkerSupportType, isSelected: Bool = false) {
        self.id = id
        self.markerName = markerName
        self.customAvatarUrl = customAvatarUrl
        self.latitude = location.latitude
        self.longitude = location.longitude
        self.markerType = markerType
        self.isSelected = isSelected
    }
    
    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, markerName,customAvatarUrl, latitude, longitude, isSelected, markerType
    }

    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)
        }
        if container.contains(.customAvatarUrl) {
            customAvatarUrl = try container.decodeIfPresent(String.self, forKey: .customAvatarUrl)
        }
        latitude = try container.decode(CGFloat.self, forKey: .latitude)
        longitude = try container.decode(CGFloat.self, forKey: .longitude)
        isSelected = try container.decode(Bool.self, forKey: .isSelected)
        
        // 使用工厂方法创建正确类型的markerType
        let rawValue = try container.decode(Int.self, forKey: .markerType)
        markerType = MarkerTypeFactory.markerType(from: rawValue)
    }

    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)
    }
}

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)
        )
    }

}
