import utime
import urandom
import math
try:
    from libs import CurrentApp
    from libs.threading import Thread
    from libs.logging import getLogger
except ImportError:
    from usr.libs import CurrentApp
    from usr.libs.threading import Thread
    from usr.libs.logging import getLogger

logger = getLogger(__name__)

class MeterService(object):

    def __init__(self, app=None):
        if app is not None:
            self.init_app(app)

    def __str__(self):
        return '{}'.format(type(self).__name__)

    def init_app(self, app):
        app.register('meter_service', self)

    def load(self):
        Thread(target=self.start_update).start()

    def random_float(self, 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

    def start_update(self):
        while True:
            data = {}
                  
            switch = True
            data.update({1: switch})

            total_forward_energy = self.random_float(6000, 6600, 2)
            data.update({2: total_forward_energy})

            total_reverse_energy = self.random_float(1000, 1500, 2)
            data.update({3: total_reverse_energy})

            # 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 = self.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 = self.random_float(4500, 5500, 2)
            com_reverse_active_energy = self.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 = self.random_float(700, 1000, 2) + self.random_float(700, 1000, 2) + self.random_float(700, 1000, 2)
            com_forward_reactive_energy = self.random_float(700, 1500, 2)
            com_reverse_reactive_energy = self.random_float(int(com_total_reactive_energy - com_forward_reactive_energy), int(com_total_reactive_energy - com_forward_reactive_energy), 2)
            data.update({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
                            }}
                        )
            
            # phase_a
            voltage_a = 220.0
            current_a = self.random_float(9, 10, 2)
            power_factor_a = self.random_float(1, 99, 2)
            active_power_a = self.random_float(2000, 2200, 2)
            reactive_power_a = self.random_float(600, 700, 2)
            frequency_phase_a = 50.00
            data.update({5: {1: voltage_a,
                            2: current_a,
                            3: active_power_a,
                            4: reactive_power_a,
                            5: frequency_phase_a,
                            6: power_factor_a
                            }}
                        )
            
            # phase_b
            voltage_b = 220.0
            current_b = self.random_float(9, 10, 2)
            power_factor_b = self.random_float(1, 199, 2)
            active_power_b = self.random_float(2000, 2200, 2)
            reactive_power_b = self.random_float(600, 700, 2)
            frequency_phase_b = 50.00
            data.update({6: {1: voltage_b,
                            2: current_b,
                            3: active_power_b,
                            4: reactive_power_b,
                            5: frequency_phase_b,
                            6: power_factor_b
                            }}
                        )
            
            # phase_c
            voltage_c = 220.0
            current_c = self.random_float(9, 10, 2)
            power_factor_c = self.random_float(1, 99, 2)
            active_power_c = self.random_float(2000, 2200, 2)
            reactive_power_c = self.random_float(600, 700, 2)
            frequency_phase_c = 50.00
            data.update({7: {1: voltage_c,
                            2: current_c,
                            3: active_power_c,
                            4: reactive_power_c,
                            5: frequency_phase_c,
                            6: power_factor_c
                            }}
                        )
            
            total_active_power = self.random_float(int(active_power_a + active_power_b + active_power_c), int(active_power_a + active_power_b + active_power_c), 2)
            data.update({8: total_active_power})

            total_reactive_power = self.random_float(int(reactive_power_a + reactive_power_b + reactive_power_c), int(reactive_power_a + reactive_power_b + reactive_power_c), 2)
            data.update({9: total_reactive_power})

            power_factor = 0.95
            data.update({10: power_factor})

            balance_energy = self.random_float(0, 999999, 2)
            data.update({11: balance_energy})

            leakage_current = self.random_float(0, 999999, 2)
            data.update({12: leakage_current})

            temperature = self.random_float(45, 55, 2)
            data.update({13: temperature})

            switch_prepayment = True
            data.update({14: switch_prepayment})

            charge_energy = self.random_float(0, 999999, 2)
            data.update({15: charge_energy})

            clear_energy = True
            data.update({16: clear_energy})

            reclose_cnt = urandom.randint(1, 30)
            data.update({17: reclose_cnt})

            reclose_enable = True
            data.update({18: reclose_enable})

            reclose_time = urandom.randint(0, 600)
            data.update({19: reclose_time})

            power_up_reclose_time = urandom.randint(1, 600)
            data.update({20: power_up_reclose_time})

            fault = 0
            data.update({21: fault})

            # 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)
            data.update({22: {1: alarm_over_voltage_relay_off_enable,
                            2: alarm_over_voltage_thr,
                            3: alarm_over_voltage_delay,
                            4: alarm_over_voltage_protect_delay
                            }}
                        )
            
            # 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)
            data.update({23: {1: alarm_over_current_relay_off_enable,
                            2: alarm_over_current_thr,
                            3: alarm_over_current_delay,
                            4: alarm_over_current_protect_delay
                            }}
                        )
            
            # 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)
            data.update({24: {1: alarm_under_voltage_relay_off_enable,
                            2: alarm_under_voltage_thr,
                            3: alarm_under_voltage_delay,
                            4: alarm_under_voltage_protect_delay
                            }}
                        )
            
            # 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)
            data.update({25: {1: alarm_vottage_unbalance_relay_off_enalbe,
                            2: alarm_voltage_unbalance_thr,
                            3: alarm_voltage_unbalance_delay,
                            4: alarm_voltage_unbalance_protect_delay
                            }}
                        )
            
            # 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)
            data.update({26: {1: alarm_current_unbalance_relay_off_enable,
                            2: alarm_current_unbalance_thr,
                            3: alarm_current_unbalance_delay,
                            4: alarm_current_unbalance_protect_delay
                            }}
                        )
            
            # 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)
            data.update({27: {1: alarm_miss_phase_relay_off_enable,
                            2: alarm_miss_phase_delay,
                            3: alarm_miss_phase_protect_delay
                            }})
            
            # 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)
            data.update({28: {1: alarm_rev_phase_relay_off_enable,
                            2: alarm_rev_phase_delay,
                            3: alarm_rev_phase_protect_delay
                        }}
                        )
            
            # 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)
            data.update({29: {1: alarm_low_current_relay_off_enable,
                            2: alarm_low_current_thr,
                            3: alarm_low_current_delay,
                            4: alarm_low_current_protect_delay
                        }}
                        )

            if data:
                with CurrentApp().qth_client:
                    for _ in range(3):
                        if CurrentApp().qth_client.sendTsl(1, data):
                            break
                    else:
                        logger.debug("send meter data to qth server fail, next report will be after 2 seconds")
                        utime.sleep(2)
                        continue

                    logger.debug('send meter data to qth server success, next report will be after 30 seconds')
                    utime.sleep(30)