#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
手机连接器模块
用于接收手机传送的摄像头图像、GPS位置和设备信息
"""

import cv2
import numpy as np
import json
import time
import threading
from datetime import datetime
import base64
import socket
import struct
from typing import Dict, List, Optional, Tuple, Callable
from . import config

class MobileDevice:
    """移动设备信息类"""
    def __init__(self, device_id: str, device_name: str):
        self.device_id = device_id
        self.device_name = device_name
        self.last_seen = time.time()
        self.is_online = True
        self.current_location = None  # (lat, lng, accuracy)
        self.battery_level = 100
        self.signal_strength = 100
        self.camera_info = {}
        self.connection_info = {}
        
    def update_status(self, data: dict):
        """更新设备状态"""
        self.last_seen = time.time()
        self.is_online = True
        
        if 'gps' in data:
            self.current_location = (
                data['gps'].get('latitude'),
                data['gps'].get('longitude'),
                data['gps'].get('accuracy', 0)
            )
        
        if 'battery' in data:
            self.battery_level = data['battery']
            
        if 'signal' in data:
            self.signal_strength = data['signal']
            
        if 'camera_info' in data:
            self.camera_info = data['camera_info']
    
    def is_location_valid(self) -> bool:
        """检查GPS位置是否有效"""
        if not self.current_location:
            return False
        lat, lng, _ = self.current_location
        return lat is not None and lng is not None and -90 <= lat <= 90 and -180 <= lng <= 180

class MobileConnector:
    """手机连接器主类"""
    
    def __init__(self, port: int = 8080):
        self.port = port
        self.server_socket = None
        self.is_running = False
        self.devices = {}  # device_id -> MobileDevice
        self.frame_callbacks = []  # 帧数据回调函数列表
        self.location_callbacks = []  # 位置数据回调函数列表
        self.device_callbacks = []  # 设备状态回调函数列表
        self.client_threads = []
        
        # 统计信息
        self.total_frames_received = 0
        self.total_data_received = 0
        self.start_time = time.time()
        
    def add_frame_callback(self, callback: Callable):
        """添加帧数据回调函数"""
        self.frame_callbacks.append(callback)
    
    def add_location_callback(self, callback: Callable):
        """添加位置数据回调函数"""
        self.location_callbacks.append(callback)
    
    def add_device_callback(self, callback: Callable):
        """添加设备状态回调函数"""
        self.device_callbacks.append(callback)
    
    def start_server(self):
        """启动服务器"""
        try:
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.server_socket.bind(('0.0.0.0', self.port))
            self.server_socket.listen(5)
            self.is_running = True
            
            print(f"📱 手机连接服务器启动成功，端口: {self.port}")
            print(f"🌐 等待手机客户端连接...")
            
            # 启动服务器监听线程
            server_thread = threading.Thread(target=self._server_loop, daemon=True)
            server_thread.start()
            
            # 启动设备状态监控线程
            monitor_thread = threading.Thread(target=self._device_monitor, daemon=True)
            monitor_thread.start()
            
            return True
            
        except Exception as e:
            print(f"❌ 启动服务器失败: {e}")
            return False
    
    def stop_server(self):
        """停止服务器"""
        self.is_running = False
        if self.server_socket:
            self.server_socket.close()
        
        # 清理客户端连接
        for thread in self.client_threads:
            if thread.is_alive():
                thread.join(timeout=1.0)
        
        print("📱 手机连接服务器已停止")
    
    def _server_loop(self):
        """服务器主循环"""
        while self.is_running:
            try:
                client_socket, address = self.server_socket.accept()
                print(f"📱 新的手机客户端连接: {address}")
                
                # 为每个客户端创建处理线程
                client_thread = threading.Thread(
                    target=self._handle_client,
                    args=(client_socket, address),
                    daemon=True
                )
                client_thread.start()
                self.client_threads.append(client_thread)
                
            except Exception as e:
                if self.is_running:
                    print(f"⚠️ 服务器接受连接时出错: {e}")
                break
    
    def _handle_client(self, client_socket, address):
        """处理客户端连接"""
        device_id = None
        try:
            while self.is_running:
                # 接收数据长度
                length_data = self._recv_all(client_socket, 4)
                if not length_data:
                    break
                    
                data_length = struct.unpack('!I', length_data)[0]
                
                # 接收JSON数据
                json_data = self._recv_all(client_socket, data_length)
                if not json_data:
                    break
                
                try:
                    data = json.loads(json_data.decode('utf-8'))
                    device_id = data.get('device_id')
                    
                    if device_id:
                        self._process_mobile_data(device_id, data, address)
                        self.total_data_received += len(json_data)
                        
                except json.JSONDecodeError as e:
                    print(f"⚠️ JSON解析错误: {e}")
                    continue
                    
        except Exception as e:
            print(f"⚠️ 处理客户端 {address} 时出错: {e}")
        finally:
            client_socket.close()
            if device_id and device_id in self.devices:
                self.devices[device_id].is_online = False
                print(f"📱 设备 {device_id} 已断开连接")
    
    def _recv_all(self, socket, length):
        """接收指定长度的数据"""
        data = b''
        while len(data) < length:
            packet = socket.recv(length - len(data))
            if not packet:
                return None
            data += packet
        return data
    
    def _process_mobile_data(self, device_id: str, data: dict, address):
        """处理手机发送的数据"""
        # 更新或创建设备信息
        if device_id not in self.devices:
            device_name = data.get('device_name', f'Mobile-{device_id[:8]}')
            self.devices[device_id] = MobileDevice(device_id, device_name)
            print(f"📱 新设备注册: {device_name} ({device_id[:8]})")
            
            # 触发设备状态回调
            for callback in self.device_callbacks:
                try:
                    callback('device_connected', self.devices[device_id])
                except Exception as e:
                    print(f"⚠️ 设备回调错误: {e}")
        
        device = self.devices[device_id]
        device.update_status(data)
        device.connection_info = {'address': address}
        
        # 处理图像数据
        if 'frame' in data:
            try:
                frame_data = base64.b64decode(data['frame'])
                frame = cv2.imdecode(
                    np.frombuffer(frame_data, np.uint8), 
                    cv2.IMREAD_COLOR
                )
                
                if frame is not None:
                    self.total_frames_received += 1
                    
                    # 触发帧数据回调
                    for callback in self.frame_callbacks:
                        try:
                            callback(device_id, frame, device)
                        except Exception as e:
                            print(f"⚠️ 帧回调错误: {e}")
                            
            except Exception as e:
                print(f"⚠️ 图像数据处理错误: {e}")
        
        # 处理GPS位置数据
        if 'gps' in data and device.is_location_valid():
            for callback in self.location_callbacks:
                try:
                    callback(device_id, device.current_location, device)
                except Exception as e:
                    print(f"⚠️ 位置回调错误: {e}")
    
    def _device_monitor(self):
        """设备状态监控"""
        while self.is_running:
            try:
                current_time = time.time()
                offline_devices = []
                
                for device_id, device in self.devices.items():
                    # 超过30秒没有数据认为离线
                    if current_time - device.last_seen > 30:
                        if device.is_online:
                            device.is_online = False
                            offline_devices.append(device_id)
                
                # 通知离线设备
                for device_id in offline_devices:
                    print(f"📱 设备 {device_id[:8]} 已离线")
                    for callback in self.device_callbacks:
                        try:
                            callback('device_disconnected', self.devices[device_id])
                        except Exception as e:
                            print(f"⚠️ 设备回调错误: {e}")
                
                time.sleep(5)  # 每5秒检查一次
                
            except Exception as e:
                print(f"⚠️ 设备监控错误: {e}")
                time.sleep(5)
    
    def get_online_devices(self) -> List[MobileDevice]:
        """获取在线设备列表"""
        return [device for device in self.devices.values() if device.is_online]
    
    def get_device_by_id(self, device_id: str) -> Optional[MobileDevice]:
        """根据ID获取设备"""
        return self.devices.get(device_id)
    
    def get_statistics(self) -> dict:
        """获取连接统计信息"""
        online_count = len(self.get_online_devices())
        total_count = len(self.devices)
        uptime = time.time() - self.start_time
        
        return {
            'online_devices': online_count,
            'total_devices': total_count,
            'frames_received': self.total_frames_received,
            'data_received_mb': self.total_data_received / (1024 * 1024),
            'uptime_seconds': uptime,
            'avg_frames_per_second': self.total_frames_received / uptime if uptime > 0 else 0
        }
    
    def send_command_to_device(self, device_id: str, command: dict):
        """向指定设备发送命令（预留接口）"""
        # TODO: 实现向手机发送控制命令的功能
        pass 