"""
VehicleStatusPublisher 測試程式

測試從 vehicle_registry 讀取資料並發布到 ROS2 topics
"""

import time
import json
import threading

# ROS2 imports
import rclpy
from rclpy.node import Node

# 標準 ROS2 消息類型
import std_msgs.msg
import sensor_msgs.msg
import geometry_msgs.msg
import mavros_msgs.msg

# 專案 imports
from ..fc_network_adapter.mavlinkROS2Nodes import (
    VehicleStatusPublisher,
    fc_ros_manager,
    ros2_manager
)
from ..fc_network_adapter.mavlinkVehicleView import (
    vehicle_registry,
    ConnectionType,
    ComponentType,
)


class TestSubscriber(Node):
    """測試用的訂閱者節點 - 接收並記錄收到的消息"""
    
    def __init__(self, sysid: int = 1):
        super().__init__(f'test_subscriber_sys{sysid}')
        
        self.sysid = sysid
        self.received_messages = {
            'position': [],
            'attitude': [],
            'velocity': [],
            'battery': [],
            'vfr_hud': [],
            'mode': [],
            'summary': [],
        }
        
        # 建立所有訂閱者
        self._create_subscriptions()
        
        print(f"[TestSubscriber] 已建立，監聽 sys{sysid} 的所有 topics")
    
    def _create_subscriptions(self):
        """建立所有 topic 的訂閱者"""
        
        base_topic = f'{VehicleStatusPublisher.topicString_prefix}/sys{self.sysid}'
        
        # Position
        self.create_subscription(
            sensor_msgs.msg.NavSatFix,
            f'{base_topic}/position',
            lambda msg: self._on_message('position', msg),
            10
        )
        
        # Attitude
        self.create_subscription(
            sensor_msgs.msg.Imu,
            f'{base_topic}/attitude',
            lambda msg: self._on_message('attitude', msg),
            10
        )
        
        # Velocity
        self.create_subscription(
            geometry_msgs.msg.TwistStamped,
            f'{base_topic}/velocity',
            lambda msg: self._on_message('velocity', msg),
            10
        )
        
        # Battery
        self.create_subscription(
            sensor_msgs.msg.BatteryState,
            f'{base_topic}/battery',
            lambda msg: self._on_message('battery', msg),
            10
        )
        
        # VFR HUD
        self.create_subscription(
            mavros_msgs.msg.VfrHud,
            f'{base_topic}/vfr_hud',
            lambda msg: self._on_message('vfr_hud', msg),
            10
        )
        
        # Mode
        self.create_subscription(
            std_msgs.msg.String,
            f'{base_topic}/mode',
            lambda msg: self._on_message('mode', msg),
            10
        )
        
        # Summary
        self.create_subscription(
            std_msgs.msg.String,
            f'{base_topic}/summary',
            lambda msg: self._on_message('summary', msg),
            10
        )
    
    def _on_message(self, topic_name: str, msg):
        """通用消息接收回調"""
        self.received_messages[topic_name].append(msg)
        print(f"[TestSubscriber] 收到 {topic_name}: {self._format_msg(topic_name, msg)}")
    
    def _format_msg(self, topic_name: str, msg) -> str:
        """格式化消息以便顯示"""
        if topic_name == 'position':
            return f"lat={msg.latitude:.6f}, lon={msg.longitude:.6f}, alt={msg.altitude:.2f}m"
        elif topic_name == 'attitude':
            return f"quat=({msg.orientation.x:.3f}, {msg.orientation.y:.3f}, {msg.orientation.z:.3f}, {msg.orientation.w:.3f})"
        elif topic_name == 'velocity':
            return f"linear=({msg.twist.linear.x:.2f}, {msg.twist.linear.y:.2f}, {msg.twist.linear.z:.2f})"
        elif topic_name == 'battery':
            return f"voltage={msg.voltage:.2f}V, percent={msg.percentage*100:.1f}%"
        elif topic_name == 'vfr_hud':
            return f"airspeed={msg.airspeed:.2f}, groundspeed={msg.groundspeed:.2f}, heading={msg.heading}"
        elif topic_name == 'mode':
            return f"mode={msg.data}"
        elif topic_name == 'summary':
            try:
                data = json.loads(msg.data)
                return f"sysid={data['sysid']}, socket_id={data['socket_id']}, mode={data['mode_name']}"
            except:
                return msg.data
        return str(msg)
    
    def get_message_count(self, topic_name: str) -> int:
        """獲取收到的消息數量"""
        return len(self.received_messages[topic_name])
    
    def clear_messages(self):
        """清空已收到的消息"""
        for key in self.received_messages:
            self.received_messages[key].clear()


def setup_test_vehicle(sysid: int = 1, socket_id: int = 10):
    """
    建立測試用的載具數據
    
    Args:
        sysid: 系統 ID
        socket_id: Socket ID
    """
    print(f"\n=== 建立測試載具 (sysid={sysid}, socket_id={socket_id}) ===")
    
    # 註冊載具
    vehicle = vehicle_registry.register(sysid)
    vehicle.kind = "Copter"
    vehicle.vehicle_type = 2  # MAV_TYPE_QUADROTOR
    vehicle.connected_via = ConnectionType.UDP
    vehicle.custom_meta['socket_id'] = socket_id
    
    # 新增 autopilot 組件 (component_id=1)
    autopilot = vehicle.add_component(1, ComponentType.AUTOPILOT)
    autopilot.mav_type = 2  # MAV_TYPE_QUADROTOR
    autopilot.mav_autopilot = 3  # MAV_AUTOPILOT_ARDUPILOTMEGA
    
    # 填充狀態資料
    status = autopilot.status
    
    # 位置
    status.position.latitude = 25.0330
    status.position.longitude = 121.5654
    status.position.altitude = 100.5
    status.position.relative_altitude = 50.0
    status.position.timestamp = time.time()
    
    # 姿態
    status.attitude.roll = 0.1
    status.attitude.pitch = -0.05
    status.attitude.yaw = 1.57
    status.attitude.rollspeed = 0.01
    status.attitude.pitchspeed = 0.02
    status.attitude.yawspeed = 0.03
    status.attitude.timestamp = time.time()
    
    # 飛行模式
    status.mode.base_mode = 89
    status.mode.custom_mode = 4
    status.mode.mode_name = "GUIDED"
    status.mode.timestamp = time.time()
    
    # 電池
    status.battery.voltage = 12.6
    status.battery.current = 15.3
    status.battery.remaining = 75
    status.battery.temperature = 35.2
    status.battery.timestamp = time.time()
    
    # GPS
    status.gps.fix_type = 3  # 3D fix
    status.gps.satellites_visible = 12
    status.gps.eph = 100
    status.gps.epv = 150
    status.gps.timestamp = time.time()
    
    # VFR
    status.vfr.airspeed = 5.5
    status.vfr.groundspeed = 6.0
    status.vfr.heading = 90
    status.vfr.throttle = 65
    status.vfr.climb = 1.2
    status.vfr.timestamp = time.time()
    
    # 系統狀態
    status.armed = True
    status.system_status = 4  # MAV_STATE_ACTIVE
    
    # 更新封包統計
    autopilot.update_packet_stats(seq=10, msg_type=33, timestamp=time.time())
    
    print(f"✓ 載具 {sysid} 已建立並填充測試數據")
    return vehicle


def test_basic_publishing():
    """測試基本的發布功能"""
    print("\n" + "="*60)
    print("測試 1: 基本發布功能")
    print("="*60)
    
    # 清空 registry
    vehicle_registry.clear()
    
    # 建立測試載具
    vehicle = setup_test_vehicle(sysid=1, socket_id=10)
    
    # 初始化 ROS2 管理器
    if not ros2_manager.initialized:
        ros2_manager.initialize()
    
    # 建立測試訂閱者
    test_sub = TestSubscriber(sysid=1)
    
    # 啟動 publisher
    ros2_manager.start()
    
    print("\n--- 開始發布，等待 5 秒 ---")
    
    # 運行 5 秒，持續 spin
    start_time = time.time()
    while time.time() - start_time < 5.0:
        rclpy.spin_once(test_sub, timeout_sec=0.1)
        time.sleep(0.1)
    
    # 檢查收到的消息
    print("\n--- 消息統計 ---")
    total_messages = 0
    for topic in ['position', 'attitude', 'velocity', 'battery', 'vfr_hud', 'mode', 'summary']:
        count = test_sub.get_message_count(topic)
        total_messages += count
        print(f"  {topic:15s}: {count:3d} 條消息")
    
    print(f"\n總計收到: {total_messages} 條消息")
    
    # 驗證
    if total_messages > 0:
        print("\n✓ 測試通過：成功接收到消息")
    else:
        print("\n✗ 測試失敗：沒有接收到任何消息")
    
    # 停止
    ros2_manager.stop()
    test_sub.destroy_node()


def test_frequency_control():
    """測試頻率控制功能"""
    print("\n" + "="*60)
    print("測試 2: 頻率控制")
    print("="*60)
    
    # 清空 registry
    vehicle_registry.clear()
    
    # 建立測試載具
    vehicle = setup_test_vehicle(sysid=1, socket_id=10)
    
    # 初始化（如果還沒初始化）
    if not ros2_manager.initialized:
        ros2_manager.initialize()
    
    # 建立測試訂閱者
    test_sub = TestSubscriber(sysid=1)

    # 修改頻率設定
    publisher_node = ros2_manager.status_publisher
    publisher_node.rate_controller.topic_intervals = {
        'position': 1.5,   
        'attitude': 1.0,    
        'velocity': 1.0,     
        'battery': 1.0,   
        'vfr_hud': 0.5,    
        'mode': 0.0,       
        'summary': 0.0,    
    }
    
    # 啟動 publisher
    ros2_manager.start()
    
    print("\n--- 測試頻率控制，運行 3 秒 ---")
    
    # 運行 3 秒
    start_time = time.time()
    while time.time() - start_time < 3.0:
        rclpy.spin_once(test_sub, timeout_sec=0.1)
        time.sleep(0.1)
    
    # 檢查頻率
    print("\n--- 頻率分析 ---")
    print("預期：position 約 2 條 (0.67Hz)，attitude/battery/velocity 約 3 條 (1Hz)，vfr_hud 約 6 條 (2Hz) mode/summary 不發布")
    
    print("2Hz Topics (預期 ~6 條):")
    for topic in ['position', 'attitude', 'velocity', 'vfr_hud']:
        count = test_sub.get_message_count(topic)
        print(f"  {topic:15s}: {count:3d} 條")
    for topic in ['battery', 'mode', 'summary']:
        count = test_sub.get_message_count(topic)
        print(f"  {topic:15s}: {count:3d} 條")
    
    print("\n✓ 頻率控制測試完成")
    
    # 停止
    ros2_manager.stop()
    test_sub.destroy_node()


def test_multi_vehicle():
    """測試多載具發布"""
    print("\n" + "="*60)
    print("測試 3: 多載具發布")
    print("="*60)
    
    # 清空 registry
    vehicle_registry.clear()
    
    # 建立 3 個測試載具
    v1 = setup_test_vehicle(sysid=1, socket_id=10)
    v2 = setup_test_vehicle(sysid=2, socket_id=11)
    v3 = setup_test_vehicle(sysid=3, socket_id=12)
    
    # 修改各載具的位置以便區分
    v2.components[1].status.position.latitude = 26.0
    v3.components[1].status.position.latitude = 27.0
    
    # 初始化
    if not ros2_manager.initialized:
        ros2_manager.initialize()
    
    # 建立 3 個測試訂閱者
    test_sub1 = TestSubscriber(sysid=1)
    test_sub2 = TestSubscriber(sysid=2)
    test_sub3 = TestSubscriber(sysid=3)
    
    # 啟動 publisher
    ros2_manager.start()
    
    print("\n--- 測試多載具，運行 3 秒 ---")
    
    # 運行 3 秒
    start_time = time.time()
    while time.time() - start_time < 3.0:
        rclpy.spin_once(test_sub1, timeout_sec=0.05)
        rclpy.spin_once(test_sub2, timeout_sec=0.05)
        rclpy.spin_once(test_sub3, timeout_sec=0.05)
        time.sleep(0.1)
    
    # 檢查每個載具的消息
    print("\n--- 各載具消息統計 ---")
    for sysid, test_sub in [(1, test_sub1), (2, test_sub2), (3, test_sub3)]:
        total = sum(test_sub.get_message_count(t) for t in test_sub.received_messages.keys())
        print(f"載具 {sysid}: {total:3d} 條消息")
        
        # 檢查 summary 中的 socket_id
        if test_sub.get_message_count('summary') > 0:
            last_summary = test_sub.received_messages['summary'][-1]
            data = json.loads(last_summary.data)
            print(f"  └─ socket_id={data['socket_id']}, lat={data['latitude']:.1f}")
    
    print("\n✓ 多載具測試完成")
    
    # 停止
    ros2_manager.stop()
    test_sub1.destroy_node()
    test_sub2.destroy_node()
    test_sub3.destroy_node()


def test_dynamic_vehicle():
    """測試動態新增/移除載具"""
    print("\n" + "="*60)
    print("測試 4: 動態載具管理")
    print("="*60)
    
    # 清空 registry
    vehicle_registry.clear()
    
    # 初始化
    if not ros2_manager.initialized:
        ros2_manager.initialize()
    
    # 建立測試訂閱者
    test_sub = TestSubscriber(sysid=1)
    
    # 啟動 publisher
    ros2_manager.start()
    
    print("\n--- 階段 1: 無載具，運行 1 秒 ---")
    start_time = time.time()
    while time.time() - start_time < 1.0:
        rclpy.spin_once(test_sub, timeout_sec=0.1)
        time.sleep(0.1)
    
    count_before = sum(test_sub.get_message_count(t) for t in test_sub.received_messages.keys())
    print(f"收到消息: {count_before} 條")
    
    # 新增載具
    print("\n--- 階段 2: 新增載具，運行 2 秒 ---")
    vehicle = setup_test_vehicle(sysid=1, socket_id=10)
    
    start_time = time.time()
    while time.time() - start_time < 2.0:
        rclpy.spin_once(test_sub, timeout_sec=0.1)
        time.sleep(0.1)
    
    count_after = sum(test_sub.get_message_count(t) for t in test_sub.received_messages.keys())
    print(f"收到消息: {count_after - count_before} 條")
    
    # 移除載具
    print("\n--- 階段 3: 移除載具，運行 1 秒 ---")
    vehicle_registry.unregister(1)
    
    start_time = time.time()
    while time.time() - start_time < 1.0:
        rclpy.spin_once(test_sub, timeout_sec=0.1)
        time.sleep(0.1)
    
    count_final = sum(test_sub.get_message_count(t) for t in test_sub.received_messages.keys())
    print(f"收到消息: {count_final - count_after} 條（應該為 0）")
    
    if count_final - count_after == 0:
        print("\n✓ 動態載具管理測試通過")
    else:
        print("\n✗ 移除載具後仍收到消息")
    
    # 停止
    ros2_manager.stop()
    test_sub.destroy_node()


def main():
    """主測試函數"""
    print("\n" + "="*60)
    print("VehicleStatusPublisher 測試程式")
    print("="*60)
    
    try:
        # 執行各項測試
        test_basic_publishing()
        # time.sleep(1)
        
        # test_frequency_control()
        # time.sleep(1)
        
        # test_multi_vehicle()
        # time.sleep(1)
        
        # test_dynamic_vehicle()
        
        print("\n" + "="*60)
        print("所有測試完成！")
        print("="*60)
        
    except KeyboardInterrupt:
        print("\n\n測試被中斷")
    except Exception as e:
        print(f"\n\n測試出錯: {e}")
        import traceback
        traceback.print_exc()
    finally:
        # 清理
        if ros2_manager.initialized:
            ros2_manager.shutdown()
        vehicle_registry.clear()
        print("\n清理完成")


if __name__ == '__main__':
    main()
