# 系统库
import datetime
import queue
import signal
import sys
from pathlib import Path
from google.protobuf import json_format
import threading
import time

# 自己的封装
import pykit.library.mqttkit as mqtt_kit
import pykit.library.selectkit as select_kit
import pykit.library.suidkit as suid_kit
import pykit.library.sqlkit as sql_kit
# 基本类
from tables import Satellite
from tables import SatelliteWork
import protopy.TDSCmd_pb2 as TDSCmd_pb
import protopy.mod_satellite_pb2 as mod_satellite_pb

# ini文件初始化
conf = suid_kit.ParserStartIni(str(Path(__file__).absolute().parent))
conf.Read('utf-8')  # utf-8 因为有中文注释
# suid 初始化对象
suidKey = suid_kit.ParserSUID(conf.SUIDHeaderInt())
suidKey.GenSUID(conf.SUIDHeaderInt(), 1, 0)

# 子系统id
systemId = suid_kit.SystemID.Server
# suid 整型
suid = suidKey.suidInt

# 初始化 mqtt client 参数
[local_broker, local_port] = conf.LocalMqtt()
[cloud_broker, cloud_port] = conf.CloudMqtt()
localParam = mqtt_kit.ConnectParam(local_broker, local_port, hex(suid))
cloudParam = mqtt_kit.ConnectParam(cloud_broker, cloud_port, hex(suid))
# client 对象初始化
local = mqtt_kit.newClient(localParam)
cloud = mqtt_kit.newClient(cloudParam)

# 收发队列初始化
sendQueue = queue.PriorityQueue()
receiveQueue = queue.PriorityQueue()


# 根据suid生成topic
def getTopic(suid, level):
    suidstr = hex(suid)
    return '/' + '/'.join(suidstr[2:2 + level])


# mqtt订阅
def on_message(client, userdata, msg):
    cmdsub = TDSCmd_pb.TDSCmd()
    cmdsub.ParseFromString(msg.payload)

    receiveQueue.put_nowait((150 - cmdsub.priority, cmdsub))


# print(suidKey.GetSubTopic(4))
mqtt_kit.subscribe(local, suidKey.GetSubTopic(4), on_message)
mqtt_kit.subscribe(cloud, suidKey.GetSubTopic(4), on_message)

# 接口函数
dao = sql_kit.Dao('mysql+pymysql://root:lhr@192.168.0.210:3306/test')


def api(cmd: TDSCmd_pb.TDSCmd):
    iid = cmd.interface_id
    cmd2 = TDSCmd_pb.TDSCmd()
    cmd2.src_suid = cmd.dst_suid
    cmd2.dst_suid = cmd.src_suid
    cmd2.priority = cmd.priority
    cmd2.interface_id = iid + 1
    cmd2.ts.GetCurrentTime()
    sat = Satellite()
    if iid == 10101:  # 执行新增
        sat.norad = iid + 10
        dao.Add(sat)
        rows = dao.select(Satellite, Satellite.norad == sat.norad)
        print([row.to_dict() for row in rows])
    elif iid == 10103:  # 执行修改
        sat.norad = '25544'
        sat.enName = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
        dao.Update(Satellite, sat, Satellite.norad == sat.norad)
        rows = dao.select(Satellite, Satellite.norad == sat.norad)
        print([row.to_dict() for row in rows])
    elif iid == 10105:  # 执行删除，先请求增加
        sat.norad = iid + 6
        dao.Del(Satellite, Satellite.norad == sat.norad)
        rows = dao.select(Satellite, Satellite.norad == sat.norad)
        print([row.to_dict() for row in rows])
    elif iid == 10107:  # 查询数据并返回请求方
        rows = dao.select(Satellite, Satellite.norad is not None)
        for row in rows:
            cmd2.parameters.add().Pack(row.to_proto())  # message -> any
        print([row.to_dict() for row in rows])
    elif iid == 10109:  # 双表查询并打印
        rows = dao.multi_select(SatelliteWork, Satellite, Satellite.norad is not None)
        print(rows)
        for row in rows:
            print(row[0].to_dict(), row[1].to_dict())
    elif iid == 10111:  # 接收带参数的报文，并解析为对应的对象，最后转换为可存入数据库的对象存入数据库
        sat2 = mod_satellite_pb.RetSatelliteElement()
        for i in cmd.parameters:
            i.Unpack(sat2)  # any -> message
            sat.back_proto(sat2)
            print(sat.to_dict())
            # print(json_format.MessageToJson(sat2))
            dao.Add(sat)

    sendQueue.put_nowait((150 - cmd2.priority, cmd2))
    json_format.MessageToJson(cmd2)


# 根据suid确定站级，用于判断使用local或cloud
def checkSuid(suid):
    id = hex(suid)[2:]
    if id[2] != 0:
        return 3
    elif id[1] != 0:
        return 2
    else:
        return 1


# 接收队列处理
def receive():
    # time.sleep(2)
    while True:
        if not receiveQueue.empty():
            _, v = receiveQueue.get_nowait()
            # print(f"Receive `{v}`")
            api(v)
        time.sleep(1)


# 发送队列处理
def send():
    # print('send')
    while True:
        if not sendQueue.empty():
            _, v = sendQueue.get_nowait()
            # print(f"Send `{v}`")

            srcL = checkSuid(v.src_suid)
            dstL = checkSuid(v.dst_suid)

            topic = getTopic(v.dst_suid, 4)
            # print(topic)
            if srcL == dstL:
                local.publish(topic, v.SerializeToString())
            elif (srcL == 1 and dstL != 1) or (srcL != 1 and dstL == 1):
                cloud.publish(topic, v.SerializeToString())
        time.sleep(1)


def main():
    # 启动收发队列处理线程
    s = threading.Thread(target=send, daemon=True)
    r = threading.Thread(target=receive, daemon=True)
    s.start()
    r.start()


if __name__ == '__main__':
    print(dir(dao.session))
    main()

    # 退出前断开mqtt连接，关闭数据库连接
    def quit():
        local.disconnect()
        cloud.disconnect()
        dao.close()


    # 退出信号
    select_kit.run(quit)
