import requests
import json
import math
import webbrowser
import os
from typing import List, Tuple, Dict
import time

class MapManager:
    """高德地图管理器 - 处理地图显示和坐标标记"""
    
    def __init__(self, api_key: str = None, camera_lat: float = None, camera_lng: float = None):
        self.api_key = api_key or "your_gaode_api_key_here"  # 需要替换为真实的API key
        self.camera_lat = camera_lat or 39.9042  # 默认北京天安门坐标
        self.camera_lng = camera_lng or 116.4074
        self.camera_heading = 0  # 摄像头朝向角度（正北为0度）
        self.camera_fov = 60  # 摄像头视场角度
        self.persons_positions = []  # 人员位置列表
        self.map_html_path = "person_tracking_map.html"
        
    def set_camera_position(self, lat: float, lng: float, heading: float = 0):
        """设置摄像头位置和朝向"""
        self.camera_lat = lat
        self.camera_lng = lng
        self.camera_heading = heading
        print(f"📍 摄像头位置已设置: ({lat:.6f}, {lng:.6f}), 朝向: {heading}°")
    
    def calculate_person_position(self, pixel_x: float, pixel_y: float, distance: float, 
                                frame_width: int, frame_height: int) -> Tuple[float, float]:
        """根据人在画面中的像素位置和距离，计算真实地理坐标"""
        # 将像素坐标转换为相对角度
        horizontal_angle_per_pixel = self.camera_fov / frame_width
        
        # 计算人相对于摄像头中心的角度偏移
        center_x = frame_width / 2
        horizontal_offset_degrees = (pixel_x - center_x) * horizontal_angle_per_pixel
        
        # 计算人相对于摄像头的实际角度
        person_bearing = (self.camera_heading + horizontal_offset_degrees) % 360
        
        # 将距离和角度转换为地理坐标偏移
        person_lat, person_lng = self._calculate_destination_point(
            self.camera_lat, self.camera_lng, distance, person_bearing
        )
        
        return person_lat, person_lng
    
    def _calculate_destination_point(self, lat: float, lng: float, distance: float, bearing: float) -> Tuple[float, float]:
        """根据起点坐标、距离和方位角计算目标点坐标，使用球面几何学计算"""
        # 地球半径（米）
        R = 6371000
        
        # 转换为弧度
        lat1 = math.radians(lat)
        lng1 = math.radians(lng)
        bearing_rad = math.radians(bearing)
        
        # 计算目标点坐标
        lat2 = math.asin(
            math.sin(lat1) * math.cos(distance / R) +
            math.cos(lat1) * math.sin(distance / R) * math.cos(bearing_rad)
        )
        
        lng2 = lng1 + math.atan2(
            math.sin(bearing_rad) * math.sin(distance / R) * math.cos(lat1),
            math.cos(distance / R) - math.sin(lat1) * math.sin(lat2)
        )
        
        return math.degrees(lat2), math.degrees(lng2)
    
    def add_person_position(self, pixel_x: float, pixel_y: float, distance: float, 
                          frame_width: int, frame_height: int, person_id: str = None):
        """添加人员位置"""
        lat, lng = self.calculate_person_position(pixel_x, pixel_y, distance, frame_width, frame_height)
        
        person_info = {
            'id': person_id or f"person_{len(self.persons_positions) + 1}",
            'lat': lat,
            'lng': lng,
            'distance': distance,
            'timestamp': time.time(),
            'pixel_x': pixel_x,
            'pixel_y': pixel_y
        }
        
        self.persons_positions.append(person_info)
        
        # 只保留最近10秒的数据
        current_time = time.time()
        self.persons_positions = [
            p for p in self.persons_positions 
            if current_time - p['timestamp'] < 10
        ]
        
        return lat, lng
    
    def clear_persons(self):
        """清空人员位置"""
        self.persons_positions = []
    
    def add_person_at_coordinates(self, lat: float, lng: float, person_id: str, 
                                 distance: float = 0, source: str = "manual"):
        """直接在指定GPS坐标添加人员标记"""
        person_data = {
            'id': person_id,
            'lat': lat,
            'lng': lng,
            'distance': distance,
            'timestamp': time.time(),
            'source': source  # 标记数据来源（如设备ID）
        }
        
        # 添加到人员数据列表
        self.persons_positions.append(person_data)
        
        # 只保留最近10秒的数据
        current_time = time.time()
        self.persons_positions = [
            p for p in self.persons_positions 
            if current_time - p['timestamp'] < 10
        ]
        
        return lat, lng
    
    def get_persons_data(self) -> List[Dict]:
        """获取当前人员数据"""
        return self.persons_positions
    
    def generate_map_html(self) -> str:
        """生成高德地图HTML页面"""
        persons_data_json = json.dumps(self.persons_positions)
        
        html_content = f"""<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>实时人员位置追踪系统 🚁</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key={self.api_key}"></script>
    <style>
        body {{ margin: 0; padding: 0; }}
        #mapContainer {{ width: 100%; height: 100vh; }}
        .info-panel {{
            position: absolute;
            top: 10px;
            left: 10px;
            background: rgba(0,0,0,0.8);
            color: white;
            padding: 15px;
            border-radius: 8px;
            font-family: Arial, sans-serif;
            min-width: 250px;
            z-index: 1000;
        }}
        .status {{ color: #00ff00; }}
        .warning {{ color: #ffaa00; }}
        .info {{ color: #00aaff; }}
    </style>
</head>
<body>
    <div id="mapContainer"></div>
    <div class="info-panel">
        <h3>🚁 无人机战场态势感知</h3>
        <div class="status">● 摄像头在线</div>
        <div class="info">📍 坐标: {self.camera_lat:.6f}, {self.camera_lng:.6f}</div>
        <div class="info">🧭 朝向: {self.camera_heading}°</div>
        <div class="warning" id="personCount">👥 检测到: {len(self.persons_positions)} 人</div>
        <div style="margin-top: 10px; font-size: 12px;">
            🔴 红点 = 人员位置<br>
            📷 蓝点 = 摄像头位置<br>
            ⚡ 实时更新
        </div>
    </div>

    <script>
        // 初始化地图
        var map = new AMap.Map('mapContainer', {{
            zoom: 18,
            center: [{self.camera_lng}, {self.camera_lat}],
            mapStyle: 'amap://styles/darkblue'
        }});

        // 添加地图控件
        // map.addControl(new AMap.Scale());  // 临时注释掉以避免API兼容性问题
        // map.addControl(new AMap.ToolBar());
        
        // 摄像头标记
        var cameraMarker = new AMap.Marker({{
            position: [{self.camera_lng}, {self.camera_lat}],
            icon: new AMap.Icon({{
                size: new AMap.Size(32, 32),
                image: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png'
            }}),
            title: '摄像头位置'
        }});
        
        map.add(cameraMarker);
        
        // 人员数据
        var personsData = {persons_data_json};
        var personMarkers = [];
        
        // 添加人员标记
        personsData.forEach(function(person, index) {{
            var marker = new AMap.Marker({{
                position: [person.lng, person.lat],
                icon: new AMap.Icon({{
                    size: new AMap.Size(24, 24),
                    image: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_r.png'
                }}),
                title: '人员 ' + person.id + ' - 距离: ' + person.distance.toFixed(1) + 'm'
            }});
            
            personMarkers.push(marker);
            map.add(marker);
        }});
        
        // 定时刷新页面以更新数据
        setTimeout(function() {{
            location.reload();
        }}, 3000);
    </script>
</body>
</html>"""
        
        # 保存HTML文件
        with open(self.map_html_path, 'w', encoding='utf-8') as f:
            f.write(html_content)
        
        return self.map_html_path
    
    def open_map(self):
        """在浏览器中打开地图"""
        html_path = self.generate_map_html()
        file_url = f"file://{os.path.abspath(html_path)}"
        webbrowser.open(file_url)
        print(f"🗺️ 地图已在浏览器中打开: {html_path}")
    
    def update_camera_heading(self, new_heading: float):
        """更新摄像头朝向"""
        self.camera_heading = new_heading
        print(f"🧭 摄像头朝向已更新: {new_heading}°") 