//
//  ArrowPolylineRenderer.swift
//  map_mapkit_ios
//
//  Created by 诺诺诺的言 on 2025/7/14.
//

import UIKit
import MapKit
import Combine


class ArrowPolylineRenderer: MKPolylineRenderer {
    // 箭头属性
    var arrowColor: UIColor = .red
    var arrowSize: CGFloat = 8
    var arrowSpacing: CGFloat = 30
    
    // 边框属性
    var borderWidth: CGFloat = 0 {
        didSet {
            invalidatePath()
        }
    }
    
    var borderColor: UIColor = .clear {
        didSet {
            invalidatePath()
        }
    }
    
    override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
         // 1. 绘制边框（如果启用）
         if borderWidth > 0 {
             context.saveGState()
             
             // 设置边框样式
             context.setLineWidth(lineWidth + borderWidth * 2)
             context.setStrokeColor(borderColor.cgColor)
             context.setLineCap(lineCap)
             context.setLineJoin(lineJoin)
             
             // 创建路径并描边
             let path = createPath(for: polyline, in: mapRect, zoomScale: zoomScale)
             context.addPath(path)
             context.strokePath()
             
             context.restoreGState()
         }
         
         // 2. 绘制主线条
         super.draw(mapRect, zoomScale: zoomScale, in: context)
         
         // 3. 绘制箭头
         drawArrows(mapRect: mapRect, zoomScale: zoomScale, in: context)
     }
    
    
    private func createPath(for polyline: MKPolyline, in mapRect: MKMapRect, zoomScale: MKZoomScale) -> CGPath {
        let path = CGMutablePath()
        let points = polyline.points()
        
        // 添加第一个点
        let firstPoint = self.point(for: points[0])
        path.move(to: firstPoint)
        
        // 添加剩余点
        for i in 1..<polyline.pointCount {
            let point = self.point(for: points[i])
            path.addLine(to: point)
        }
        
        return path
    }
    
    private func drawArrows(mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
        guard polyline.pointCount >= 2 else { return }
        
        let scaledArrowSize = arrowSize / zoomScale
        let scaledArrowSpacing = arrowSpacing / zoomScale
        
        var distance: CGFloat = 0
        let points = polyline.points()
        
        for i in 0..<polyline.pointCount-1 {
            let startPoint = point(for: points[i])
            let endPoint = point(for: points[i+1])
            
            let dx = endPoint.x - startPoint.x
            let dy = endPoint.y - startPoint.y
            let segmentLength = hypot(dx, dy)
            
            guard segmentLength > 2 / zoomScale else { continue }
            
            let arrowCount = Int(floor((distance + segmentLength) / scaledArrowSpacing))
            
            for j in 0..<arrowCount {
                let position = CGFloat(j) * scaledArrowSpacing - distance
                let ratio = position / segmentLength
                
                guard ratio >= 0 && ratio <= 1 else { continue }
                
                let arrowPoint = CGPoint(
                    x: startPoint.x + dx * ratio,
                    y: startPoint.y + dy * ratio
                )
                
                let angle = atan2(dy, dx)
                drawSingleArrow(at: arrowPoint, angle: angle, size: scaledArrowSize, in: context)
            }
            
            distance = (distance + segmentLength).truncatingRemainder(dividingBy: scaledArrowSpacing)
        }
    }
    
    private func drawSingleArrow(at point: CGPoint, angle: CGFloat, size: CGFloat, in context: CGContext) {
        context.saveGState()
        context.translateBy(x: point.x, y: point.y)
        context.rotate(by: angle)
        
        let arrowPath = UIBezierPath()
        arrowPath.move(to: CGPoint(x: 3.2, y: 0))
        arrowPath.addLine(to: CGPoint(x: 0, y: 2.6))
        arrowPath.addLine(to: CGPoint(x: -3.2, y: 2.6))
        arrowPath.addLine(to: CGPoint(x: 0, y: 0))
        arrowPath.addLine(to: CGPoint(x: -3.2, y: -2.6))
        arrowPath.addLine(to: CGPoint(x: 0, y: -2.6))
        arrowPath.close()
        
        context.setFillColor(arrowColor.cgColor)
        context.addPath(arrowPath.cgPath)
        context.fillPath()
        context.restoreGState()
    }
}
