from json.decoder import JSONDecodeError
import os
import json
import logging
import importlib

from datetime import datetime, timedelta
from .eeg_python_utils import errors, time_utils

LICENSE_DOCKER_PATH = os.environ['LICENSE_DOCKER_PATH']

LICENSE_EVENT_LOG_PATH = os.environ['LICENSE_EVENT_LOG_PATH']

LICENSE_LOG_TYPE_PATHS = {
    'event_log': LICENSE_EVENT_LOG_PATH,
}

LICENSE_LOG_TYPE_FILENAMES = {
    'event_log': '{}_license_events_{}.log',
}

# init logger
license_logger = logging.getLogger('LexiServer.license')
handler = logging.FileHandler(LICENSE_EVENT_LOG_PATH)
formatter = logging.Formatter('%(asctime)s: %(message)s')
handler.setFormatter(formatter)
license_logger.addHandler(handler)
license_logger.setLevel(logging.INFO)


def set_license(new_license_file):
    print(os.path.abspath(LICENSE_DOCKER_PATH))
    new_license_file.save(os.path.abspath(LICENSE_DOCKER_PATH))
    license_status = get_license()
    if license_status is None:
        license_logger.warn('A license was uploaded but getting it returns None')
    else:
        license_id = get_license_id(license_status)
        license_not_valid_after = get_not_valid_after(license_status)
        license_stream_quantity = get_license_stream_quantity(license_status)
        license_type = 'Usage-based' if is_usage_report_unit(license_status) else 'Stream-based'

        license_logger.info(f'New license has been set with the following information: id={license_id}, expires={license_not_valid_after}, streamquantity={license_stream_quantity}, type={license_type}')


def get_license():
    try:
        with open(LICENSE_DOCKER_PATH, 'r', encoding='utf-8') as f:
            dict = json.load(f)
            return dict
    except (IOError, JSONDecodeError):
        return None


def get_license_id(license_status=None):
    if license_status is None:
        license_status = get_license()
        if license_status is None:
            return None
    license_id = license_status.get('id', None)
    return license_id


def get_license_stream_quantity(license_status=None):
    if license_status is None:
        license_status = get_license()
        if license_status is None:
            return None
    # license_stream_quantity is represented as a String in the license.
    license_stream_quantity = license_status.get('unitquantity', '0')
    license_stream_quantity = int(license_stream_quantity)
    return license_stream_quantity


def delete_license():
    try:
        os.remove(LICENSE_DOCKER_PATH)
    except OSError as e:
        errors.forbidden(str(e))


def get_valid_from(license_status=None):
    if license_status is None:
        license_status = get_license()
        if license_status is None:
            return None
    validFrom = license_status.get('metadata',{}).get('request',{}).get('validFrom','')
    return validFrom


def get_not_valid_after(license_status=None):
    if license_status is None:
        license_status = get_license()
        if license_status is None:
            return None
    notValidAfter = license_status.get('metadata', {}).get('request', {}).get('notValidAfter', '')
    return notValidAfter


def is_licensed(license_status=None):
    if license_status is None:
        license_status = get_license()
        if license_status is None:
            return False
    return license_status.get('signedclaimstoken', '') != ''


def is_license_early(license_status=None):
    if license_status is None:
        license_status = get_license()
        if license_status is None:
            return False

    validFrom = get_valid_from()
    if validFrom is None or validFrom == '':
        return False

    license_start_date = datetime.strptime(validFrom,"%Y-%m-%d")
    present = datetime.now()

    if present.date() > license_start_date.date():
        return False
    return True


def is_license_expired(license_status=None):
    if license_status is None:
        license_status = get_license()
        if license_status is None:
            return False

    notValidAfter = get_not_valid_after()
    if notValidAfter is None or notValidAfter == '':
        return False

    # Add 1 day to notValidAfter since the license isn't valid after the day terminates.
    # Aka, the license expires the start of the next day.
    validUntil = datetime.strptime(notValidAfter, "%Y-%m-%d") + timedelta(days=1)
    present = datetime.now()

    if present.date() < validUntil.date():
        return False
    return True


def get_license_log_type_filenames():
    return list(LICENSE_LOG_TYPE_PATHS.keys())


def get_license_log_file_path(log_type):
    log_path = LICENSE_LOG_TYPE_PATHS[log_type]
    license_id = get_license_id()
    log_filename = LICENSE_LOG_TYPE_FILENAMES[log_type]\
        .format(license_id, time_utils.now_string(file=True))
    return log_path, log_filename


# The DR mode is based on the Product Name file
# DR is enabled if the unit is 'Lexi DR'
def is_disaster_recover_unit():
    product_name = importlib.import_module('modules.system').get_product_name()
    is_disaster_recovery_unit = product_name == 'Lexi DR'

    return is_disaster_recovery_unit


# The Usage Report is based on the License
# Usage Report is enabled if the License has 'unittype' = 'Hours'
def is_usage_report_unit(license_status=None):
    license_content = get_license()

    if license_status is None and license_content is None:
        return False

    is_usage_report_unit = license_content.get('unittype') == 'Hours'

    return is_usage_report_unit


# To use Lexi you need to have a valid license which means both
# 1) Is licensed
# and
# 2) Is not expired
def has_a_valid_license_status():
    unit_licensed = is_licensed()
    unit_expired = is_license_expired()

    valid_status = unit_licensed and not unit_expired

    return valid_status
