import time
import uuid
import subprocess
from datetime import datetime, timezone

from scripts.config.app_constants import CommonKeys, CommonConstants


class CommonUtils(CommonKeys, CommonConstants):

    @staticmethod
    def get_utc_datetime_now():
        return datetime.utcnow()

    @staticmethod
    def ui_datetime_format_key():
        # %Y-%m-%d %H:%M:%S
        return 'ui_datetime_format'

    @staticmethod
    def utc_datetime_format_key():
        # %Y-%m-%dT%H:%M:%SZ
        return 'utc_datetime_format'

    @staticmethod
    def no_special_chars_datetime_format_key():
        # %Y%m%d%H%M%S
        return 'no_special_chars_datetime_format'

    @staticmethod
    def user_meta_time_format_key():
        # %d-%m-%Y %H:%M:%S
        return 'user_meta_time_format'

    @staticmethod
    def user_meta_time_format_ws_key():
        # %d-%m-%Y %H:%M:%S
        return 'user_meta_time_format_ws'

    def ui_datetime_format(self):
        return self.__ui_datetime_format__

    def utc_datetime_format(self):
        return self.__utc_datetime_format__

    def no_special_chars_datetime_format(self):
        return self.__no_special_chars_datetime_format__

    def user_meta_time_format(self):
        return self.__user_meta_time_format__

    def user_meta_time_format_ws(self):
        return self.__user_meta_time_format_ws__

    def get_datetime_str(self, dt=None, dt_format='user_meta_time_format'):
        """
        Returns the datetime string.
        :param dt: The datetime value to be converted as str. If not passes, Current UTC time will be returned.
        :param dt_format: The format to which the date string should be converted. 'utc_datetime_format' is the default.
                Supported values are:- 'ui_datetime_format', 'utc_datetime_format', 'no_special_chars_datetime_format',
                'user_meta_time_format'
        :return: Datetime string
        """
        if dt is None:
            dt = self.get_utc_datetime_now()
        return dt.strftime(getattr(self, dt_format)())

    def get_datetime_dt(self, dt_str, dt_format='user_meta_time_format'):
        return datetime.strptime(date_string=dt_str, format=getattr(self, dt_format)())

    @staticmethod
    def get_epoch_now(_round=True):
        if _round:
            return int(time.time())
        else:
            return time.time()

    @staticmethod
    def system_timezone():
        return datetime.now(timezone.utc).astimezone().tzname()

    @staticmethod
    def get_mac_id():
        return ':'.join(['{:02x}'.format((uuid.getnode() >> ele) & 0xff) for ele in range(0, 8 * 6, 8)][::-1])

    @staticmethod
    def get_mac_if_wo_colon():
        return ''.join(['{:02x}'.format((uuid.getnode() >> ele) & 0xff) for ele in range(0, 8 * 6, 8)][::-1])

    @staticmethod
    def ssl_protocol(ssl_enabled=False):
        if ssl_enabled:
            return 'https'
        else:
            return 'http'

    def get_user_meta(self, input_data, check_flag=False):
        """
        Function to get the metadata for all database entries
        :param input_data: input_data
        :param check_flag: Existing data, if any False else True
        :return:
        """
        data_for_meta = input_data
        if check_flag:
            data_for_meta[self.KEY_CREATED_BY] = input_data["user_id"]
            data_for_meta[self.KEY_CREATED_TIME] = self.get_datetime_str()
            data_for_meta[self.KEY_LAST_UPDATED_BY] = input_data["user_id"]
            data_for_meta[self.KEY_LAST_UPDATED_TIME] = self.get_datetime_str()
        else:
            data_for_meta[self.KEY_LAST_UPDATED_BY] = input_data["user_id"]
            data_for_meta[self.KEY_LAST_UPDATED_TIME] = self.get_datetime_str()
        return data_for_meta

    @staticmethod
    def execute_subprocess(command):
        return subprocess.Popen(command,
                                shell=True,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.STDOUT)

    @staticmethod
    def get_time_tuple():
        return (datetime.now().timetuple().tm_year,
                datetime.now().timetuple().tm_mon,
                datetime.now().timetuple().tm_mday,
                datetime.now().timetuple().tm_hour,
                datetime.now().timetuple().tm_min,
                datetime.now().timetuple().tm_sec,
                0)

    def get_unix_timezone(self):
        out, err = self.execute_subprocess('timedatectl | grep "Time zone"').communicate()
        return out.decode().split(':')[1].split('(')[0].strip()

