import rclpy
from pymavlink import mavutil
from time import sleep
import time

import socket
import struct

# used at fdm_switch_example_two
import threading
import queue

def mavlink_analyzer_simple(count = 500):
    # rclpy.init()
    # node = rclpy.create_node('mavlink_analyzer_simple')
 
    print('Inintializing connection')

    connection_string="udp:127.0.0.1:14550"
    connection = mavutil.mavlink_connection(connection_string)

    print('Catch messages')
    msg_count = {}

    start_time = time.time()

    for _ in range(count):
        msg = connection.recv_msg()
        # msg = connection.recv_match(blocking=True)
        if msg:
            msg_type = msg.get_type()
            if msg_type in msg_count:
                msg_count[msg_type] += 1
            else:
                msg_count[msg_type] = 1

            if msg.get_type() == 'SERVO_OUTPUT_RAW':
                print(msg)
                pass

        else:
            print('No message yet, 1 second for data to fill')
            sleep(1)

    print("markA ------")
    print(msg.get_type())
    print(msg.ordered_fieldnames)
    print("markA ------ END")

    print('Messages Type received:')
    print(msg_count)

    end_time = time.time()
    print('Time elapsed: ', end_time - start_time)

    print('Closing connection')
    connection.close()


def fdm_parser_example(data=None):
    if data is None:
        data = bytes.fromhex('1a48e903b1340500e803e803e803e803000000000000000000000000000000000000000000000000')
    # 1a48e903b1340500e803e803e803e803000000000000000000000000000000000000000000000000

    parse_format = 'HHI16H'

    if len(data) != struct.calcsize(parse_format):
        print("got packet of len %u, expected %u" % (len(data), struct.calcsize(parse_format)))
        exit(1)

    decoded = struct.unpack(parse_format,data)

    magic = decoded[0]
    frame_rate_hz = decoded[1]
    frame_count = decoded[2]
    pwm = decoded[3:]


    print("magic: %u, frame_rate_hz: %u, frame_count: %u, pwm: %s" % (magic, frame_rate_hz, frame_count, pwm))

def fdm_switch_example_one():

    '''
    這個範例在 SITL 與 Gazebo 之間 做一個簡單的UDP轉發器 
    沒有轉換數據格式
    '''
    # make a link get fdm from SITL, as a server
    sock_s2g = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock_s2g.bind(('', 9002))
    sock_s2g.settimeout(0.1)

    # set a target link pass JSON to Gazebo, as a client
    sock_g2s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    server_address = ('127.0.0.1', 19002)

    packet_count = 0
    start_time = time.time()

    while True:
        try:
            # 接到SITL的數據 並轉發給Gazebo
            data_s2g, addr_s2g = sock_s2g.recvfrom(1024)
            sock_g2s.sendto(data_s2g, server_address)
            # 得到Gazebo的回應 並轉發給SITL
            data_g2s, addr_g2s = sock_g2s.recvfrom(1024)
            sock_s2g.sendto(data_g2s, addr_s2g)
            packet_count += 1
        except socket.timeout:
            pass

        current_time = time.time()
        elapsed_time = current_time - start_time

        if elapsed_time >= 1.0:
            # print(f"Packets received in the last second: {packet_count}")
            print(f'JSON Pack : {data_g2s}')
            packet_count = 0
            start_time = current_time
            fdm_parser_example(data_s2g)


def fdm_switch_example_two():
    '''
    這個範例在 SITL 與 Gazebo 之間 做一個簡單的UDP轉發器 
    有轉換數據格式

    time_usec
    servo1_raw 
    servo16_raw
    '''
    # read info from SITL via MAVLink
    connection_string="udp:127.0.0.1:14550" # uart mavlink  # MATLAB
    connection = mavutil.mavlink_connection(connection_string)

    # set a target link pass JSON to Gazebo, as a client
    sock_g2s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    server_address = ('127.0.0.1', 19002)

    data_queue = queue.Queue()
    servo_out = [0] * 16 # [0 0 0 0 0 0 0 0 0.....]
    data_queue.put(servo_out)

    def send_data_from_queue(sock, server_address, q, frame_rate_fdm=1, frame_count_fdm=1):
        interval = 1.0 / frame_rate_fdm
        while True:
            start_time = time.time()
            try:
                data = q.get(timeout=0.1) # [0 0 0 0 0 0 0 0 0.....]
                if data is None:
                    break
                last_data = data
            except queue.Empty:
                data = last_data
            data_fdm = struct.pack('HHI16H', 0x481a, int(frame_rate_fdm * 0.1), frame_count_fdm, *servo_out) # [ FMD ]
            sock.sendto(data_fdm, server_address)
            frame_count_fdm += 3
            # fdm_parser_example(data_fdm) # debug

            elapsed_time = time.time() - start_time
            sleep_time = interval - elapsed_time
            if sleep_time > 0:
                sleep(sleep_time)

    Running = True
    thread = threading.Thread(target=send_data_from_queue, args=(sock_g2s, server_address, data_queue))
    thread.start()
    print('Start sending data to Gazebo')

    while Running:
        msgb1 = None
        msg = connection.recv_msg()
        while msg :
            if msg.get_type() == 'SERVO_OUTPUT_RAW':
                msgb1 = msg
                # break # 這裡不需要break，因為我要最後一個 servo_output_raw 的值
            msg = connection.recv_msg()

        if msgb1:
            for i in range(16):
                servo_out[i] = getattr(msgb1, f'servo{i+1}_raw')
                data_queue.put(servo_out)
            msgb1 = None
            # Running = False # debug
        else:
            # print('No message yet, 10 ms for data to fill')
            sleep(0.01)

        # Example of putting data into the queue
        # data_queue.put(data)
        # To stop the thread, you can put None into the queue
        # data_queue.put(None)

from pymavlink.dialects.v20 import common  # 使用 MAVLink 2.0

def mavlink_btye_generator_test():

    # 創建一個 MAVLink 對象
    mav = common.MAVLink(None)  # 不透過 connection，直接使用 None

    # 創建一個 HEARTBEAT 訊息
    msg = mav.heartbeat_encode(
        type=mavutil.mavlink.MAV_TYPE_QUADROTOR,
        autopilot=mavutil.mavlink.MAV_AUTOPILOT_GENERIC,
        base_mode=0,
        custom_mode=0,
        system_status=mavutil.mavlink.MAV_STATE_ACTIVE
    )

    # 取得 MAVLink 訊息的 bytes
    mavlink_bytes = msg.pack(mav)

    # 回傳 bytes
    print(mavlink_bytes)
    print(type(mavlink_bytes))

    mav2 = common.MAVLink(None)
    # my_msg = mav2.decode(mavlink_bytes)
    print("========")
    print(dir(mav2))
    # print(my_msg)



print('Start')
# fdm_switch_example_two()
# fdm_parser_example()
# mavlink_analyzer_simple(8)
# mavlink_btye_generator_test()


