#!/usr/bin/env python3
from PyQt6.QtWebEngineWidgets import QWebEngineView
from PyQt6.QtCore import QTimer, pyqtSignal, QObject, pyqtSlot
from PyQt6.QtWebChannel import QWebChannel

class DroneMap:
    """無人機地圖類別 - 負責管理 Leaflet 地圖顯示"""
    
    def __init__(self):
        """初始化地圖"""
        self.map_view = QWebEngineView()
        self.map_loaded = False
        self.pending_map_updates = {}
        
        # 創建橋接對象
        self.bridge = MapBridge()
        
        # 設置 QWebChannel
        self.channel = QWebChannel()
        self.channel.registerObject('bridge', self.bridge)
        self.map_view.page().setWebChannel(self.channel)
        
        # 設置地圖 HTML
        inline_html = '''
            <!DOCTYPE html>
            <html>
            <head>
            <meta charset="utf-8" />
            <link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
            <script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
            <script src="https://unpkg.com/leaflet-rotatedmarker/leaflet.rotatedMarker.js"></script>
            <script src="qrc:///qtwebchannel/qwebchannel.js"></script>
            <style>
                html, body, #map { height: 100%; margin: 0; }
                .map-controls {
                    position: absolute;
                    top: 10px;
                    right: 10px;
                    z-index: 1000;
                }
                .control-button {
                    padding: 8px 12px;
                    background-color: #f44336;
                    color: white;
                    border: none;
                    border-radius: 4px;
                    cursor: pointer;
                    font-size: 12px;
                    box-shadow: 0 2px 5px rgba(0,0,0,0.2);
                }
                .control-button:hover {
                    background-color: #d32f2f;
                }
            </style>
            </head>
            <body>
            <div id="map"></div>
            <div class="map-controls">
                <button class="control-button" onclick="clearAllTrajectories()">清除軌跡</button>
            </div>

            <script>
                var bridge;
                new QWebChannel(qt.webChannelTransport, function(channel) {
                    bridge = channel.objects.bridge;
                });

                var map = L.map('map').setView([0, 0], 19); 
                L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
                    maxZoom: 19,
                    attribution: '© OpenStreetMap contributors'
                }).addTo(map);

                // 地圖點擊事件
                map.on('click', function(e) {
                    if (bridge) {
                        bridge.emitGpsSignal(e.latlng.lat, e.latlng.lng);
                        console.log('點擊位置:', e.latlng.lat, e.latlng.lng);
                    }
                });

                var arrowIcon = L.icon({
                    iconUrl: 'https://cdn-icons-png.flaticon.com/512/399/399308.png',
                    iconSize: [40, 40],
                    iconAnchor: [20, 20]
                });

                function getColorBySocketId(id) {
                    if (id.startsWith("s0_")) return "#00BFFF";  // 天藍色
                    if (id.startsWith("s1_")) return "#FFD700";  // 金色
                    if (id.startsWith("s2_")) return "#FF6969";  // 淺紅色
                    if (id.startsWith("s3_")) return "#FF69B4";  // 熱粉紅
                    if (id.startsWith("s4_")) return "#00FA9A";  // 中春綠
                    if (id.startsWith("s5_")) return "#9370DB";  // 中紫色 (串口)
                    if (id.startsWith("s6_")) return "#FFA500";  // 橙色
                    if (id.startsWith("s7_")) return "#20B2AA";  // 淺海綠
                    if (id.startsWith("s8_")) return "#7CFC00";  // 草綠色
                    if (id.startsWith("s9_")) return "#FF8C00";  // 深橙色
                    return "#AAAAAA";  // 灰色 (預設)
                }

                function createIdIcon(id) {
                    const color = getColorBySocketId(id);
                    const sysid = id.split('_')[1];
                    return L.divIcon({
                        className: 'drone-id',
                        html: `<div style="
                            position: relative;
                            left: 2px;
                            background-color: ${color};
                            color: black;
                            width: 16px;
                            height: 16px;
                            border-radius: 50%;
                            display: flex;
                            align-items: center;
                            justify-content: center;
                            font-weight: bold;
                            font-size: 10px;
                            ">${sysid}</div>`,
                        iconSize: [20, 20],
                        iconAnchor: [10, 10]
                    });
                }

                var markers = {};
                var idLabels = {};
                var trajectories = {};
                var trajectoryLines = {};
                var focusedId = null;
                var initialized = false;
                var trajectoryGroup = L.layerGroup().addTo(map);

                function initTrajectory(id) {
                    if (!trajectories[id]) {
                        trajectories[id] = [];
                        const color = getColorBySocketId(id);
                        trajectoryLines[id] = L.polyline([], {
                            color: color,
                            weight: 3,
                            opacity: 0.7,
                            smoothFactor: 1
                        }).addTo(trajectoryGroup);
                    }
                }

                function addTrajectoryPoint(id, lat, lon) {
                    initTrajectory(id);
                    const point = [lat, lon];
                    trajectories[id].push(point);
                    
                    if (trajectories[id].length > 1000) {
                        trajectories[id].shift();
                    }
                    
                    trajectoryLines[id].setLatLngs([...trajectories[id]]);
                }

                function focusOn(id) {
                    if (!markers[id]) return;
                    focusedId = id;
                    var latlng = markers[id].getLatLng();
                    map.flyTo(latlng, map.getZoom());
                }

                setInterval(() => {
                    if (focusedId && markers[focusedId]) {
                        var latlng = markers[focusedId].getLatLng();
                        map.panTo(latlng);
                    }
                }, 1000);

                function updateDrone(lat, lon, id, heading) {
                    if (markers[id]) {
                        const lastPos = markers[id].getLatLng();
                        const distance = lastPos.distanceTo([lat, lon]);
                        if (distance > 1) {
                            addTrajectoryPoint(id, lat, lon);
                        }
                        
                        markers[id]
                            .setLatLng([lat, lon])
                            .setRotationAngle(heading);
                        idLabels[id].setLatLng([lat, lon]);
                    } else {
                        initTrajectory(id);
                        addTrajectoryPoint(id, lat, lon);
                        
                        markers[id] = L.marker([lat, lon], {
                            icon: arrowIcon,
                            rotationAngle: heading,
                            rotationOrigin: 'center'
                        })
                        .on('click', function () {
                            focusOn(id);
                        })
                        .addTo(map);

                        idLabels[id] = L.marker([lat, lon], {
                            icon: createIdIcon(id),
                            zIndexOffset: 1000
                        })
                        .on('click', function() {
                            focusOn(id);
                        })
                        .addTo(map);

                        if (!initialized || id < focusedId) {
                            focusOn(id);
                            initialized = true;
                        }
                    }
                }

                function clearAllTrajectories() {
                    trajectories = {};
                    Object.values(trajectoryLines).forEach(line => {
                        trajectoryGroup.removeLayer(line);
                    });
                    trajectoryLines = {};
                    console.log('所有軌跡已清除');
                }
            </script>
            </body>
            </html>
        '''
        
        self.map_view.setHtml(inline_html)
        self.map_view.loadFinished.connect(self._on_map_loaded)
        
        # 設置地圖更新計時器
        self.map_update_timer = QTimer()
        self.map_update_timer.timeout.connect(self.update_map_positions)
        self.map_update_timer.start(200)  # 每 200ms 更新一次
    
    def _on_map_loaded(self, ok: bool):
        """地圖加載完成回調"""
        if ok:
            self.map_loaded = True
        else:
            print("⚠️ 地圖加載失敗")
    
    def update_drone_position(self, drone_id, lat, lon, heading):
        """更新無人機位置（加入待處理隊列）"""
        self.pending_map_updates[drone_id] = (lat, lon, heading)
    
    def update_map_positions(self):
        """批量更新地圖上的無人機位置"""
        if not self.map_loaded or not self.pending_map_updates:
            return
        
        # 批量執行所有待更新的位置
        js_commands = []
        for drone_id, (lat, lon, heading) in self.pending_map_updates.items():
            js_commands.append(f"updateDrone({lat:.6f}, {lon:.6f}, '{drone_id}', {heading:.1f});")
        
        if js_commands:
            combined_js = "\n".join(js_commands)
            self.map_view.page().runJavaScript(combined_js)
        
        # 清空待更新緩存
        self.pending_map_updates.clear()
    
    def clear_trajectories(self):
        """清除所有軌跡"""
        if self.map_loaded:
            self.map_view.page().runJavaScript("clearAllTrajectories();")
    
    def focus_on_drone(self, drone_id):
        """聚焦到指定無人機"""
        if self.map_loaded:
            self.map_view.page().runJavaScript(f"focusOn('{drone_id}');")
    
    def get_widget(self):
        """獲取地圖 widget"""
        return self.map_view
    
    def get_gps_signal(self):
        """獲取 GPS 信號"""
        return self.bridge.gps_signal
    
class MapBridge(QObject):
    """JavaScript 和 Python 之間的橋接類"""
    gps_signal = pyqtSignal(float, float)  # lat, lon
    
    def __init__(self):
        super().__init__()
    
    @pyqtSlot(float, float)
    def emitGpsSignal(self, lat, lon):
        """供 JavaScript 調用的方法"""
        self.gps_signal.emit(lat, lon)