from usr.Qth import qth_init
from usr.Qth import qth_config
from usr.Qth import qth_bus
from usr.Qth import qth_ota
try:
    from libs.threading import Lock
    from libs.logging import getLogger
except ImportError:
    from usr.libs.threading import Lock
    from usr.libs.logging import getLogger

import urandom
import math

logger = getLogger(__name__)

def random_float(start:int, end:int, digits:int):
    r_float = 0.0
    digits_str = '9999999999999999999999999'
    if digits > len(digits_str):
        return -1
    
    while True:
        fnum = urandom.randint(0, int(digits_str[:digits]))/(math.pow(10, digits))
        if(len(str(fnum)) > digits + 2):
                continue

        inum = urandom.randint(start, end)

        r_float = inum + fnum
        if(len(str(r_float)) > (len(str(inum)) + digits + 1)):
                continue

        break
        
    return r_float

class QthClient(object):

    def __init__(self, app=None):
        self.opt_lock = Lock()
        if app:
            self.init_app(app)
    
    def __enter__(self):
        self.opt_lock.acquire()
        return self

    def __exit__(self, *args, **kwargs):
        self.opt_lock.release()

    def init_app(self, app):
        app.register("qth_client", self)
        qth_init.init()
        qth_config.setProductInfo(app.config["QTH_PRODUCT_KEY"], app.config["QTH_PRODUCT_SECRET"])
        qth_config.setServer(app.config["QTH_SERVER"])
        qth_config.setEventCb(
            {
                "devEvent": self.eventCallback, 
                "recvTrans": self.recvTransCallback, 
                "recvTsl": self.recvTslCallback, 
                "readTsl": self.readTslCallback, 
                "readTslServer": self.recvTslServerCallback,
                "ota": {
                    "otaPlan":self.otaPlanCallback,
                    "fotaResult":self.fotaResultCallback
                }
            }
        )
    
    def load(self):
        self.start()

    def start(self):
        qth_init.start()
    
    def stop(self):
        qth_init.stop()
    
    def sendTsl(self, mode, value):
        return qth_bus.sendTsl(mode, value)

    def isStatusOk(self):
        return qth_bus.state()

    def sendLbs(self, lbs_data):
        return qth_bus.sendOutsideLocation(lbs_data)
    
    def sendGnss(self, nmea_data):
        return qth_bus.sendOutsideLocation(nmea_data)

    def eventCallback(self, event, result):
        logger.info("dev event:{} result:{}".format(event, result))
        if(2== event and 0 == result):
            qth_ota.otaRequest()

    def recvTransCallback(self, value):
        ret = qth_bus.sendTrans(1, value)
        logger.info("recvTrans value:{} ret:{}".format(value, ret))

    def recvTslCallback(self, value):
        logger.info("recvTsl:{}".format(value))
        for cmdId, val in value.items():
            logger.info("recvTsl {}:{}".format(cmdId, val))
    def readTslCallback(self, ids, pkgId):
        logger.info("readTsl ids:{} pkgId:{}".format(ids, pkgId))
        value=dict()

        # combination_energy
        # 组合总有功电量 = 组合正向有功电量 - 组合反向有功电量
        # 组合总无功电量 = 组合正向无功电量 - 组合反向无功电量
        total_phase_a_energy = 2200.0
        total_phase_b_energy = 2200.0
        com_total_phase_c_energy = 2200.0

        com_total_active_energy = random_float(int(total_phase_a_energy + total_phase_b_energy + com_total_phase_c_energy), int(total_phase_a_energy + total_phase_b_energy + com_total_phase_c_energy), 2)
        com_forward_active_energy = random_float(4500, 5500, 2)
        com_reverse_active_energy = random_float(int(com_total_active_energy - com_forward_active_energy), int(com_total_active_energy - com_forward_active_energy), 2)

        com_total_reactive_energy = random_float(700, 1000, 2) + random_float(700, 1000, 2) + random_float(700, 1000, 2)
        com_forward_reactive_energy = random_float(700, 1500, 2)
        com_reverse_reactive_energy = random_float(int(com_total_reactive_energy - com_forward_reactive_energy), int(com_total_reactive_energy - com_forward_reactive_energy), 2)

        # phase_a
        voltage_a = 220.0
        current_a = random_float(9, 10, 2)
        power_factor_a = random_float(1, 99, 2)
        active_power_a = random_float(2000, 2200, 2)
        reactive_power_a = random_float(600, 700, 2)
        frequency_phase_a = 50.00

        # phase_b
        voltage_b = 220.0
        current_b = random_float(9, 10, 2)
        power_factor_b = random_float(1, 99, 2)
        active_power_b = random_float(2000, 2200, 2)
        reactive_power_b = random_float(600, 700, 2)
        frequency_phase_b = 50.00

        # phase_c
        voltage_c = 220.0
        current_c = random_float(9, 10, 2)
        power_factor_c = random_float(1, 99, 2)
        active_power_c = random_float(2000, 2200, 2)
        reactive_power_c = random_float(600, 700, 2)
        frequency_phase_c = 50.00

        # alarm_over_voltage
        alarm_over_voltage_relay_off_enable = True
        alarm_over_voltage_thr = urandom.randint(100, 400)
        alarm_over_voltage_delay = urandom.randint(0, 60)
        alarm_over_voltage_protect_delay = urandom.randint(0, 600)

        # alarm_over_current
        alarm_over_current_relay_off_enable = True
        alarm_over_current_thr = urandom.randint(60, 100)
        alarm_over_current_delay = urandom.randint(1, 60)
        alarm_over_current_protect_delay = urandom.randint(1, 600)

        # alarm_under_voltage
        alarm_under_voltage_relay_off_enable = True
        alarm_under_voltage_thr = urandom.randint(100, 240)
        alarm_under_voltage_delay = urandom.randint(1, 60)
        alarm_under_voltage_protect_delay = urandom.randint(1, 600)

        # alarm_voltage_unbalance
        alarm_vottage_unbalance_relay_off_enalbe = True
        alarm_voltage_unbalance_thr = urandom.randint(1, 100)
        alarm_voltage_unbalance_delay = urandom.randint(1, 60)
        alarm_voltage_unbalance_protect_delay = urandom.randint(1, 600)

        # alarm_current_unbalance
        alarm_current_unbalance_relay_off_enable = True
        alarm_current_unbalance_thr = urandom.randint(1, 100)
        alarm_current_unbalance_delay = urandom.randint(1, 60)
        alarm_current_unbalance_protect_delay = urandom.randint(1, 600)

        # alarm_miss_phase
        alarm_miss_phase_relay_off_enable = True
        alarm_miss_phase_delay = urandom.randint(1, 60)
        alarm_miss_phase_protect_delay = urandom.randint(1, 600)

        # alarm_rev_phase
        alarm_rev_phase_relay_off_enable = True
        alarm_rev_phase_delay = urandom.randint(1, 60)
        alarm_rev_phase_protect_delay = urandom.randint(1, 600)

        # alarm_low_current
        alarm_low_current_relay_off_enable = True
        alarm_low_current_thr = urandom.randint(1, 100)
        alarm_low_current_delay = urandom.randint(1, 60)
        alarm_low_current_protect_delay = urandom.randint(1, 600)

        for id in ids:
            if 1 == id:
                value[1]=True
            elif 2 == id:
                value[2]=random_float(6000, 6600, 2)
            elif 3 == id:
                value[3]=random_float(1000, 1500, 2)
            elif 4 == id:
                value[4]={1: com_total_active_energy,
                          2: com_forward_active_energy,
                          3: com_reverse_active_energy,
                          4: com_total_reactive_energy,
                          5: com_forward_reactive_energy,
                          6: com_reverse_reactive_energy,
                          7: total_phase_a_energy,
                          8: total_phase_b_energy,
                          9: com_total_phase_c_energy
                        }
            elif 5 == id:
                value[5]={1: voltage_a,
                          2: current_a,
                          3: power_factor_a,
                          4: active_power_a,
                          5: reactive_power_a,
                          6: frequency_phase_a
                        }
            elif 6 == id:
                value[6]={1: voltage_b,
                          2: current_b,
                          3: power_factor_b,
                          4: active_power_b,
                          5: reactive_power_b,
                          6: frequency_phase_b
                        }
            elif 7 == id:
                value[7]={1: voltage_c,
                          2: current_c,
                          3: power_factor_c,
                          4: active_power_c,
                          5: reactive_power_c,
                          6: frequency_phase_c
                        }
            elif 8 == id:
                value[8]=random_float(int(active_power_a + active_power_b + active_power_c), int(active_power_a + active_power_b + active_power_c), 2)
            elif 9 == id:
                value[9]=random_float(int(reactive_power_a + reactive_power_b + reactive_power_c), int(reactive_power_a + reactive_power_b + reactive_power_c), 2)
            elif 10 == id:
                value[10]=0.95
            elif 11 == id:
                value[11]=random_float(0, 999999, 2)   
            elif 12 == id:
                value[12]=random_float(0, 999999, 2)  
            elif 13 == id:
                value[13]=random_float(45, 55, 2)
            elif 14 == id:
                value[14]=True
            elif 15 == id:
                value[15]=random_float(0, 999999, 2)
            elif 16 == id:
                value[16]=False
            elif 17 == id:
                value[17]=urandom.randint(1, 30)
            elif 18 == id:
                value[18]=True
            elif 19 == id:
                value[19]=urandom.randint(0, 600)
            elif 20 == id:
                value[20]=urandom.randint(1, 600)
            elif 21 == id:
                value[21]=0
            elif 22 == id:
                value[22]={1: alarm_over_voltage_relay_off_enable,
                           2: alarm_over_voltage_thr,
                           3: alarm_over_voltage_delay,
                           4: alarm_over_voltage_protect_delay
                        }
            elif 23 == id:
                value[23]={1: alarm_over_current_relay_off_enable,
                           2: alarm_over_current_thr,
                           3: alarm_over_current_delay,
                           4: alarm_over_current_protect_delay
                        }
            elif 24 == id:
                value[24]={1: alarm_under_voltage_relay_off_enable,
                           2: alarm_under_voltage_thr,
                           3: alarm_under_voltage_delay,
                           4: alarm_under_voltage_protect_delay
                        }
            elif 25 == id:
                value[25]={1: alarm_vottage_unbalance_relay_off_enalbe,
                           2: alarm_voltage_unbalance_thr,
                           3: alarm_voltage_unbalance_delay,
                           4: alarm_voltage_unbalance_protect_delay
                        }
            elif 26 == id:
                value[26]={1: alarm_current_unbalance_relay_off_enable,
                           2: alarm_current_unbalance_thr,
                           3: alarm_current_unbalance_delay,
                           4: alarm_current_unbalance_protect_delay
                        }
            elif 27 == id:
                value[27]={1: alarm_miss_phase_relay_off_enable,
                           2: alarm_miss_phase_delay,
                           3: alarm_miss_phase_protect_delay
                        }
            elif 28 == id:
                value[28]={1: alarm_rev_phase_relay_off_enable,
                           2: alarm_rev_phase_delay,
                           3: alarm_rev_phase_protect_delay
                        }
            elif 29 == id:
                value[29]={1: alarm_low_current_relay_off_enable,
                           2: alarm_low_current_thr,
                           3: alarm_low_current_delay,
                           4: alarm_low_current_protect_delay
                        }
        qth_bus.ackTsl(1, value, pkgId)

    def recvTslServerCallback(self, serverId, value, pkgId):
        logger.info("recvTslServer serverId:{} value:{} pkgId:{}".format(serverId, value, pkgId))
        qth_bus.ackTslServer(1, serverId, value, pkgId)

    def otaPlanCallback(self, plans):
        logger.info("otaPlan:{}".format(plans))
        qth_ota.otaAction(1)

    def fotaResultCallback(self, comp_no, result):
        logger.info("fotaResult comp_no:{} result:{}".format(comp_no, result))
        
    def sotaInfoCallback(self, comp_no, version, url, md5, crc):
        logger.info("sotaInfo comp_no:{} version:{} url:{} md5:{} crc:{}".format(comp_no, version, url, md5, crc))
        # 当使用url下载固件完成，且MCU更新完毕后，需要获取MCU最新的版本信息，并通过setMcuVer进行更新
        qth_bus.setMcuVer("MCU1", "V1.0.0", self.sotaInfoCallback, self.sotaResultCallback)

    def sotaResultCallback(comp_no, result):
        logger.info("sotaResult comp_no:{} result:{}".format(comp_no, result))
