import re
import time
from cacheout import LFUCache
from enum import Enum
from typing import Any
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from tornado.iostream import IOStream

from lib.struct import PayResSignal
from lib.frame import RsuFrame
from lib.handler import HADLER_MAP
from lib.format import FormatLocalDataManager,FormatManager,FormatUtils
from lib.push import PushBookKeepOperate,PushQueueOperate
from lib.config_manager import ConfigMangaer,ConfigModuleEnum
from lib.definition import ResSelect,TaskSelect
from lib.frame import TerFrame
from utils import split,FrameFilter
from log import Logger
logger = Logger(__name__)

CM = ConfigMangaer()

configByrsu = CM.load(ConfigModuleEnum.RSU_MODULE)
configByappBusiness = CM.load(ConfigModuleEnum.APP_BUSINESS_MODULE)

class Api(Enum):
    API_PUSH_DEV_ONLANE = "/api/v1/dev/platform/park/dev/status/push/"
    API_GET_WORK_KEY = "/api/v1/gateway/platform/public/get/work/key/"

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


async def handler(rf:RsuFrame,stream:IOStream,cache:LFUCache,hadnlerCache:LFUCache,reqOperate)->Any:
    cmdTypeStr = rf.cmdType.hex()
    HADNLER_FUN = HADLER_MAP.get(cmdTypeStr)
    if not HADNLER_FUN:
        logger.error(f"捕获到未定义帧代码:{cmdTypeStr}")
        return ResSelect.E13
    kwargs = {}
    if cmdTypeStr == "d0":
        kwargs = {
            "keyFrameLogPath":configByappBusiness["KEY_FRAME_LOG_PATH"],
            "lane":configByappBusiness["LANE"],
            "rsuId":configByrsu["RSU_ID"],
            "parkId":configByappBusiness["PARK_ID"],
            "isEnablePlatesDiff":configByappBusiness["ENABLE_PLATES_DIFF"]
        }
    elif cmdTypeStr == "d1":
        kwargs = {
            "rsuId":configByrsu["RSU_ID"]
            }
    elif cmdTypeStr == "d2":
        kwargs = {
            "devNumber":configByappBusiness["DEV_NUMBER"]
            }
    elif cmdTypeStr == "91":
        kwargs = {
            "devNumber":configByappBusiness["DEV_NUMBER"]
            }
    handlerRes = await HADNLER_FUN(stream,cache,hadnlerCache,rf,reqOperate,**kwargs)
    if cmdTypeStr in ["d0","d1","d2"]:
        logger.info(f"{cmdTypeStr}帧处理结果=======>:{handlerRes.value}")
    return handlerRes


async def BusinessHandler(stream:IOStream,fr,scheduler:AsyncIOScheduler,payResSignal:PayResSignal,cache:LFUCache,handlerCache:LFUCache,reqOperate)->Any:
    '''
    @stream 天线连接句柄
    主程序开始执行
    '''
    lane = configByappBusiness["LANE"]
    parkId = configByappBusiness["PARK_ID"]
    devNumber = configByappBusiness["DEV_NUMBER"]
    # while True:
        # fr = await stream.read_bytes(1024, partial=True)
    cache.set("RSUConnectTimeout",int(time.time()))
    logger.info(re.sub(r"(?<=\w)(?=(?:\w\w)+$)", " ", fr.hex()))
    try:
        frGroup = split(fr) #分割处理粘包
    except Exception as e:
        logger.error(f"分割buf异常:{e}")
        payResSignal.SetPayResSignal(ResSelect.E13.value,lane)
        return
    frGroup = FrameFilter(frGroup) #过滤非法帧,在有交易帧时过滤心跳帧。
    for f in frGroup:
        rf = RsuFrame(f)
        if rf.isErr:
            logger.error(f"帧数据异常:{rf.errMsg}")
            payResSignal.SetPayResSignal(ResSelect.E14.value,lane)
            return

        cmdType = rf.cmdType.hex()
        try:
            handlerRes = await handler(rf,stream,cache,handlerCache,reqOperate)
        except Exception as e:
            logger.error(f"{cmdType}帧处理时捕获未知异常:{e}")
            payResSignal.SetPayResSignal(ResSelect.E13.value,lane)
            if cmdType in ["d0","d1","d2"]:
                    # tf = TerFrame(b'\x50',(b'\x80',b'\x00',b'\x02'),"!sss")
                    # stream.write(tf.frame)
                    scheduler.resume_job(TaskSelect.TASK_HEARTBEAT.value)  # 恢复心跳
                    return
        
        if cmdType in ["91","98","99"]:
            return

        if cmdType in ["d0","d1"]:
            if handlerRes != ResSelect.E00:
                if handlerRes == ResSelect.E02 and cmdType == "d0" and configByappBusiness["RUN_MODEL"] == "recover":
                    tf = TerFrame(b'\x50',(b'\x80',b'\x00',b'\x02'),"!sss")
                    stream.write(tf.frame)
                    return

                payResSignal.SetPayResSignal(handlerRes.value,lane)
                # tf = TerFrame(b'\x50',(b'\x80',b'\x00',b'\x02'),"!sss")
                # stream.write(tf.frame)
                scheduler.resume_job(TaskSelect.TASK_HEARTBEAT.value)  # 恢复心跳
                return
        
        if cmdType == "d2":
            if handlerRes != ResSelect.E00:
                payResSignal.SetPayResSignal(handlerRes.value,lane)
                # tf = TerFrame(b'\x50',(b'\x80',b'\x00',b'\x02'),"!sss")
                # stream.write(tf.frame)
                scheduler.resume_job(TaskSelect.TASK_HEARTBEAT.value)  # 恢复心跳
                return
            
            workKey = cache.get("workKey")
            order = handlerCache.get("order")
            frameDataParam = handlerCache.get("E5_frameDataParam")
            operateQueue=PushQueueOperate()
            operateBook = PushBookKeepOperate()
            fm = FormatManager()
            fml = FormatLocalDataManager()
            fm.FormatInit(handlerCache)
            fml.FormatInit(order,devNumber,parkId)
            transacData = fm.FormatTransacData(parkId,order,workKey,frameDataParam) #原生交易数据
            transacSn = transacData["transSn"]
            errCallbackBody = fml.FormatQueueErrData(transacData)
            alarmParam = FormatUtils.FormatAlarmParam(order["payNo"],transacData["programStartTime"])
            try:
                queueData = fml.FormatQueueData(transacData)
                await operateQueue.push(queueData,errCallbackBody,alarmParam)  # 即时向平台提交
            except Exception as e:
                return

            # 开始记账
            payResSignal.SetPayResSignal(ResSelect.E00.value,lane) # 设置扣款成功信号
            fml.FormatInit(order,devNumber,parkId)
            summary = fml.FormatSummaryData(transacSn,parkId)
            content = fml.FormatContentData(transacSn,1)
            try:
                await operateBook.push(content,summary,parkId)
            except Exception as e:
                return
            # tf = TerFrame(b'\x50',(b'\x80',b'\x00',b'\x02'),"!sss")
            # stream.write(tf.frame)
            scheduler.resume_job(TaskSelect.TASK_HEARTBEAT.value)  # 恢复心跳