import time
from typing import Any

from retrying_async import retry
from cacheout import LFUCache
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from tornado.tcpclient import TCPClient
from tornado.iostream import IOStream,StreamClosedError

from src.handler_manager import BusinessHandler
from lib.frame import TerFrame
from lib.struct import PayResSignal,PaySignal
from lib.config_manager import ConfigMangaer,ConfigModuleEnum
from lib.push import PushDevOnline
from lib.req import ReqOperate,CallbackByReqVehicleInfo
from lib.definition import TaskSelect
from task.job import SendHeartbeat,ETC0rderManager
from log import Logger
logger = Logger(__name__)

CM = ConfigMangaer()
configByRedis =  CM.load(ConfigModuleEnum.REDIS_MODULE)
configByrsu = CM.load(ConfigModuleEnum.RSU_MODULE)
configByappBusiness = CM.load(ConfigModuleEnum.APP_BUSINESS_MODULE)
configByAuth = CM.load(ConfigModuleEnum.AUTH_MODULE)

def handle_close(*args, **kwargs):
    # 连接关闭时的处理
    print("Connection closed")
    # 在这里添加重新连接的逻辑

class MianManager(object):
    def __init__(self) -> None:
        self.appCache = LFUCache() #运行时系统缓存
        self.handlerCache = LFUCache(ttl=5)
        self.orderManager:ETC0rderManager = None
        self._schedulerStartStatus = False
        self.heartbeatselfJob = None

    @retry(attempts=100, delay=3)
    async def __ConnectRSU(self)->IOStream:
        '''
        @rsuAddress 天线地址对象包含IP于服务端口
        return 连接句柄stream
        连接RSU天线
        '''
        logger.info("尝试连接到RSU...")
        self.stream = await TCPClient().connect(configByrsu["RSU_IP"], configByrsu["RSU_PORT"], timeout=2)
        self.appCache.set("RSUConnectTimeout",int(time.time()))
        logger.info("链接完成...")

    async def IsRSUStreamConnect(self):
        RSUConnectTimeout = self.appCache.get("RSUConnectTimeout")
        if int(time.time()) - RSUConnectTimeout > 60:
            self.stream.close()
            print("检测到RUS断开")
            

    def __RsuInit(self,power:int)->Any:
        tf = TerFrame(b'\x18',(power,),"!b")
        if tf.isErr:
            logger.error(tf.errMsg)
            return -1
        self.stream.write(tf.frame)

    def __TaskInit(self):
        self.scheduler.add_job(
            self.orderManager.get,
            'interval',
            seconds=0.05,
            id = TaskSelect.TASK_GET_ORDER.value,
            kwargs = {
                "lane":configByappBusiness["LANE"],
                "keyFrameLogPath":configByappBusiness["KEY_FRAME_LOG_PATH"]
            }
        )  # 每50毫秒发送一次检测信号
        self.heartbeatselfJob = self.scheduler.add_job(
            SendHeartbeat,
            'interval',
            seconds=configByappBusiness["INTERVAL"],
            id = TaskSelect.TASK_HEARTBEAT.value,
            kwargs = {"stream":self.stream})  # 每3秒发送一次心跳
        jobObjects = self.scheduler.get_jobs()
        jobList = [job.id for job in jobObjects]
        if TaskSelect.TASK_ISRSUSTREAMCONNECT.value not in jobList:
            self.scheduler.add_job(
                self.IsRSUStreamConnect,
                'interval',
                seconds=3,
                id = TaskSelect.TASK_ISRSUSTREAMCONNECT.value
            )

    async def init(self):
        middlewareAddress = {
            "host":configByRedis["MIDDLEWARE_IP"],
            "port":configByRedis["MIDDLEWARE_PORT"],
            "password":configByRedis["MIDDLEWARE_PWD"]}
        self.payResSignal = PayResSignal(middlewareAddress,configByappBusiness["PARK_ID"])
        self.paySignal = PaySignal(middlewareAddress,configByappBusiness["PARK_ID"])
        self.scheduler = AsyncIOScheduler() #定时任务控制器
        await self.__ConnectRSU()
        self.__RsuInit(configByrsu["RSU_POWRE"])
        self.orderManager = ETC0rderManager(self.paySignal,self.scheduler,self.stream,self.handlerCache)
        self.__TaskInit()
        self.reqOperate = ReqOperate(auth=(configByAuth["AUTH_ACCOUNT"],configByAuth["AUTH_PASSWORD"]))
        self.reqOperate.SetErrCallbackByReqVehicleInfo(CallbackByReqVehicleInfo,self.appCache,configByrsu["RSU_ID"],configByappBusiness["DEV_NUMBER"])
        logger.info("应用初始化完成")

    async def start(self):
        # pushByDeviceOnlineRes = await PushDevOnline(configByappBusiness["DEV_NUMBER"])
        # if pushByDeviceOnlineRes == -1:
        #     logger.error(f"通知平台设备上线异常,但不影响系统初始化")

        reqWorkKeyRes = await self.reqOperate.ReqWorkSm4Key(configByrsu["RSU_ID"],configByappBusiness["DEV_NUMBER"])
        if reqWorkKeyRes == -1:
            exit()
        self.appCache.set("workKey",reqWorkKeyRes)
        tf = TerFrame(b'\x50',(b'\x80',b'\x00',b'\x02'),"!sss")
        self.stream.write(tf.frame)
        try:
            if not self._schedulerStartStatus:
                self.scheduler.start()
                self._schedulerStartStatus = True
            while True:
                try:
                    fr = await self.stream.read_bytes(1024, partial=True)
                except StreamClosedError as e:
                    logger.error(f"天线连接异常:{e}")
                    self.scheduler.pause_job(TaskSelect.TASK_HEARTBEAT.value) # 暂停心跳发送心跳会使用句柄导致报错
                    await self.__ConnectRSU() # 重新连接天线获取新句柄
                    self.__RsuInit(configByrsu["RSU_POWRE"])
                    self.heartbeatselfJob.modify(kwargs={"stream":self.stream}) # 传入新句柄到心跳线程
                    self.orderManager.stream = self.stream
                    self.scheduler.resume_job(TaskSelect.TASK_HEARTBEAT.value)# 恢复心跳
                    continue
                try:
                    await BusinessHandler(self.stream,fr,self.scheduler,self.payResSignal,self.appCache,self.handlerCache,self.reqOperate) #主程序开始
                except Exception as e:
                    logger.error(f"业务处理时捕获未知异常:{e}")
                    continue
        except Exception as e:
            logger.error(f"主逻辑异常:{e}")
            exit()