"""Driver for flowmeterskid."""
import threading
import json
import time
from random import randint
import os
from device_base import deviceBase
from Channel import PLCChannel, ModbusChannel,read_tag, write_tag, TAG_DATAERROR_SLEEPTIME
import persistence
from utilities import get_public_ip_address, get_private_ip_address
from file_logger import filelogger as logger
PLC_IP_ADDRESS = "192.168.1.12"
from Tags import tags

from datetime import datetime as dt 

logger.info("flowmeterskid startup")

# GLOBAL VARIABLES
WAIT_FOR_CONNECTION_SECONDS = 20
IP_CHECK_PERIOD = 60

_ = None

CHANNELS = tags

class start(threading.Thread, deviceBase):
    """Start class required by Meshify."""

    def __init__(self, name=None, number=None, mac=None, Q=None, mcu=None, companyId=None, offset=None, mqtt=None, Nodes=None):
        """Initialize the driver."""
        threading.Thread.__init__(self)
        deviceBase.__init__(self, name=name, number=number, mac=mac, Q=Q, mcu=mcu, companyId=companyId, offset=offset, mqtt=mqtt, Nodes=Nodes)
        self.daemon = True
        self.version = "1"
        self.finished = threading.Event()
        self.force_send = False
        self.public_ip_address = ""
        self.public_ip_address_last_checked = 0
        self.private_ip_address = ""
        self.ping_counter = 0
        threading.Thread.start(self)

    # this is a required function for all drivers, its goal is to upload some piece of data
    # about your device so it can be seen on the web
    def register(self):
        """Register the driver."""
        # self.sendtodb("log", "BOOM! Booted.", 0)
        pass

    def run(self):
        # pass
        """Actually run the driver."""
        for i in range(0, WAIT_FOR_CONNECTION_SECONDS):
            print("flowmeterskid driver will start in {} seconds".format(WAIT_FOR_CONNECTION_SECONDS - i))
            time.sleep(1)
        logger.info("BOOM! Starting flowmeterskid driver...")

        self._check_ip_address()

        self.nodes["flowmeterskid_0199"] = self

        send_loops = 0
        while True:
            if self.force_send:
                logger.warning("FORCE SEND: TRUE")
            if int(time.time()) % 600 == 0 or self.force_send:
                payload = {"ts": (round(dt.timestamp(dt.now())/600)*600)*1000, "values": {}}
                resetPayload = {"ts": "", "values": {}}
                dayReset, weekReset, monthReset, yearReset = False, False, False, False
                for chan in CHANNELS:
                    val = chan.read()
                    try:
                        if chan in ["totalizer_1"]:
                            payload["values"]["day_volume"], dayReset = self.totalizeDay(val)
                            payload["values"]["week_volume"], weekReset = self.totalizeWeek(val)
                            payload["values"]["month_volume"], monthReset = self.totalizeMonth(val)
                            payload["values"]["year_volume"], yearReset = self.totalizeYear(val)
                        payload["values"][chan.mesh_name] = val
                    except Exception as e:
                        logger.error(e)
                
                self.sendToTB(json.dumps(payload))

                if dayReset:
                    resetPayload["values"]["yesterday_volume"] = payload["values"]["day_volume"]
                    resetPayload["values"]["day_volume"] = 0
                if weekReset:
                    resetPayload["values"]["last_week_volume"] = payload["values"]["week_volume"]
                    resetPayload["values"]["week_volume"] = 0
                if monthReset:
                    resetPayload["values"]["last_month_volume"] = payload["values"]["month_volume"]
                    resetPayload["values"]["month_volume"] = 0
                if yearReset:
                    resetPayload["values"]["last_year_volume"] = payload["values"]["year_volume"]
                    resetPayload["values"]["year_volume"] = 0 

                if resetPayload["values"]:
                    resetPayload["ts"] = 1 + (round(dt.timestamp(dt.now())/600)*600)*1000
                    self.sendToTB(json.dumps(resetPayload))
                
                if self.force_send:
                    self.force_send = False
    
    def flowmeterskid_sync(self, name, value):
        """Sync all data from the driver."""
        self.force_send = True
        self.sendtodb("log", "synced", 0)
        return True
    
    def saveTotalizers(self, totalizers):
        try:
            with open("/root/python_firmware/totalizers.json", "w") as t:
                json.dump(totalizers,t)
        except Exception as e:
            logger.error(e)
    
    def get_totalizers(self):
        saveFile = "/root/python_firmware/totalizers.json"
        # Check if the state file exists.
        if not os.path.exists(saveFile):
            return {
                    "day": 0,
                    "week": 0,
                    "month": 0,
                    "year": 0,
                    "lifetime": 0,
                    "dayHolding": 0,
                    "weekHolding": 0,
                    "monthHolding": 0,
                    "yearHolding": 0
                }
        try:
            with open("/root/python_firmware/totalizers.json", "r") as t:
                totalizers = json.load(t)
            if not totalizers:
                logger.info("-----INITIALIZING TOTALIZERS-----")
                totalizers = {
                    "day": 0,
                    "week": 0,
                    "month": 0,
                    "year": 0,
                    "lifetime": 0,
                    "dayHolding": 0,
                    "weekHolding": 0,
                    "monthHolding": 0,
                    "yearHolding": 0
                }
        except:
            totalizers = {
                    "day": 0,
                    "week": 0,
                    "month": 0,
                    "year": 0,
                    "lifetime": 0,
                    "dayHolding": 0,
                    "weekHolding": 0,
                    "monthHolding": 0,
                    "yearHolding": 0
                }
        return totalizers

    def totalizeDay(self,lifetime):
        totalizers = self.get_totalizers()
        now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600)
        reset = False
        value = lifetime - totalizers["dayHolding"]
        if not int(now.strftime("%d")) == int(totalizers["day"]):
            totalizers["dayHolding"] = lifetime
            totalizers["day"] = int(now.strftime("%d"))
            self.saveTotalizers(totalizers)
            reset = True
        return (value,reset)

    def totalizeWeek(self,lifetime):
        totalizers = self.get_totalizers()
        now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600)
        reset = False
        value = lifetime - totalizers["weekHolding"]
        if (not now.strftime("%U") == totalizers["week"] and now.strftime("%a") == "Sun") or totalizers["week"] == 0:
            totalizers["weekHolding"] = lifetime
            totalizers["week"] = now.strftime("%U")
            self.saveTotalizers(totalizers)
            reset = True
        return (value, reset)

    def totalizeMonth(self,lifetime):
        totalizers = self.get_totalizers()
        now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600)
        reset = False
        value = lifetime - totalizers["monthHolding"]
        if not int(now.strftime("%m")) == int(totalizers["month"]):
            totalizers["monthHolding"] = lifetime
            totalizers["month"] = now.strftime("%m")
            self.saveTotalizers(totalizers)
            reset = True
        return (value,reset)

    def totalizeYear(self,lifetime):
        totalizers = self.get_totalizers()
        now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600)
        reset = False
        value = lifetime - totalizers["yearHolding"]
        if not int(now.strftime("%Y")) == int(totalizers["year"]):
            totalizers["yearHolding"] = lifetime
            totalizers["year"] = now.strftime("%Y")
            self.saveTotalizers(totalizers)
            reset = True
        return (value, reset)