import time
from typing import Any
from retrying_async import retry
from Crypto.Cipher import DES
from Crypto.Util.Padding import pad, unpad
from enum import Enum
from lib.proxy import ProxyDataPlatform,OAuthModeEnum
from utils import AppPrint

from log import Logger
logger = Logger(__name__)
class ReqApi(Enum):
    GET_WORK_KEY = "/api/v1/gateway/platform/public/get/work/safe/key/"
    GET_VEHICLE_INFO = "/api/v1/gateway/platform/public/dec/vehinfo/"
    GET_BLACKLIST = "/api/v1/gateway/platform/park/black/list/query/"
    GET_MAC2 = "/api/v1/gateway/platform/public/get/mac/"
    GET_ORDER = "/api/v1/free/pass/platform/query/post/arrearsrecords/"
    GET_OT_TOKEN = "/api/v1/base/platform/ott/token/get/"


class ReqOperate(object):
    def __init__(self,auth:tuple) -> None:
        self.__ReqVehicleInfoErrCallbackFun = {}
        self.__auth = {"account":auth[0],"password":auth[1]}

    def SetErrCallbackByReqVehicleInfo(self,ErrCallbackFun=None,*args,**kwargs):
        self.__ReqVehicleInfoErrCallbackFun = {
            "ErrCallbackFun":ErrCallbackFun,
            "args":args,
            "kwargs":kwargs}
            
    @retry(attempts=1000, delay=0.1)
    async def ReqWorkSm4Key(self,rsuId:str,devNnumber:str)->Any:
        '''
        获取工作秘钥
        '''
        #获取动态token防止回放攻击
        getTokenApi = ReqApi.GET_OT_TOKEN.value
        httpProxyGetToken = ProxyDataPlatform(OAuthModeEnum.V2.value)
        getTokenBody = {
            "account":self.__auth["account"],
            "password":self.__auth["password"],
            "api":ReqApi.GET_WORK_KEY.value,
            "requerts_time":int(time.time()),
            "dev_number":devNnumber

        }
        getTokenRes = await httpProxyGetToken.post(getTokenApi,getTokenBody,timeOut=4)
        if httpProxyGetToken.isErr:
            if httpProxyGetToken.errMsg.find("Time")!=-1 or httpProxyGetToken.errMsg.find("time")!=1:raise RuntimeError("请求OTT超时")
            logger.error(f"请求动态token异常:{httpProxyGetToken.errMsg}")
            return -1

        #对拿到的ott解密,a为密文,b为key,ab作为传输中混淆
        cipher = DES.new(bytes.fromhex(getTokenRes["b"]), DES.MODE_ECB)
        decrypted_message = cipher.decrypt(bytes.fromhex(getTokenRes["a"]))
        OTTtoken = unpad(decrypted_message, DES.block_size).decode('utf-8')

        '''
        获取工作秘钥
        '''
        body = {
            "rsuId":rsuId,
            "token":OTTtoken
        }
        api = ReqApi.GET_WORK_KEY.value
        httpProxy = ProxyDataPlatform(OAuthModeEnum.V2.value)
        res = await httpProxy.get(api,body)
        if httpProxy.isErr:
            if httpProxyGetToken.errMsg.find("Time")!=-1 or httpProxyGetToken.errMsg.find("time")!=1:raise RuntimeError("请求OTT超时")
            logger.error(f"请求工作密钥异常:{httpProxy.errMsg}")
            return -1
        logger.info(f"工作秘钥:\n{AppPrint(res)}")
        return res

    async def ReqVehicleInfo(self,rsuId:str,ciphertext:str,random:str,tradNo:str,_issueId:str,workKey:str)->Any:
        api = ReqApi.GET_VEHICLE_INFO.value
        body = {
            "rsuId": rsuId,
            "vehicleBody": {
                "vehInfo": ciphertext,
                "random": random[8:len(random)],
                "tradNo": tradNo,
                "divCode": f"{_issueId}{_issueId}"  # 中文部分重复两遍
            },
            "frameId": "1"
        }
        headers = {"sm4-key":workKey}
        httpProxy = ProxyDataPlatform(OAuthModeEnum.V2.value)
        res = await httpProxy.post(api,body,headers=headers,timeOut=3)
        if httpProxy.isErr:
            logger.error(httpProxy.errMsg)
            err = self.__ReqVehicleInfoErrCallbackFun["ErrCallbackFun"]
            args = self.__ReqVehicleInfoErrCallbackFun["args"]
            kwargs = self.__ReqVehicleInfoErrCallbackFun["kwargs"]
            await err(self,httpProxy.errMsg,*args,**kwargs)
            return -1
        return res

    async def ReqBlackList(self,parkId:str,cardId:str,obuId:str,issueId:str)->Any:
        api = ReqApi.GET_BLACKLIST.value
        body = {
            "serviceId": parkId,
            "cardId": cardId,
            "obuId": obuId,
            "issueId": issueId
        }
        httpProxy = ProxyDataPlatform(OAuthModeEnum.V2.value)
        res = await httpProxy.post(api,body,timeOut=3)
        if httpProxy.isErr:
            logger.error(httpProxy.errMsg)
            return -1
        return res

    async def ReqMac2(self,rsuId,transacTime,passtypeRand,terminalSN,money,cardParam,workKey):
        api = ReqApi.GET_MAC2.value
        data = {
            "cardId": cardParam.cardNumber.hex(),
            "random": passtypeRand.hex(),
            "treadNo": terminalSN.hex(),
            # "money": Struct("!i").pack(order.fee).hex(),
            # "money":'{:08X}'.format(order.fee),
            "money":money,
            "time": transacTime,
            "keyInfo": "0100",
            "issueId": f"{cardParam.issued.hex()[0:8]}{cardParam.issued.hex()[0:8]}"
        }
        body = {
                "rsuId": rsuId,
                "frameId": "0",
                "getMacBody": data
            }
        httpProxy = ProxyDataPlatform(OAuthModeEnum.V2.value)
        headers = {"sm4-key":workKey}
        res = await httpProxy.post(api,body,headers=headers,timeOut=3)
        if httpProxy.isErr:
            logger.error(httpProxy.errMsg)
            return -1
        return res


async def ReqArrearsInfo(plate:str,plateColor:int)->Any:
    api = ReqApi.GET_ORDER.value
    body = {
        "plateNo":plate,
        "plateColor":plateColor
    }
    httpProxy = ProxyDataPlatform(OAuthModeEnum.V2.value)
    httpProxy.host = "49.232.211.160"
    httpProxy.port = 9000
    httpProxy.protocol = "http"
    res = await httpProxy.get(api,body,timeOut=3)
    if httpProxy.isErr:
        logger.error(httpProxy.errMsg)
        return -1
    return res



async def CallbackByReqVehicleInfo(reqOperate:ReqOperate,errMsg:str,*args,**kwargs):
    if errMsg.find("-3")!=-1:
        reqWorkKeyRes = await reqOperate.ReqWorkSm4Key(args[1],args[2])
        logger.info(f"重新获取key:{reqWorkKeyRes}")
        args[0].set("workKey",reqWorkKeyRes)