import logging

from django.utils.translation import gettext_lazy

from core.models import ConsoleAuthSettings
from core.utils import dtnow

_log = logging.getLogger(__name__)


def create_authentication_log_message(action, message, ip_addr=None):
    log_string = f'Authentication {action}'
    if ip_addr:
        log_string += f' from ip: {ip_addr}'
    log_string += f': {message}'
    return log_string


def handle_login_attempt(attempt_username_data, login_successful, ip_address):
    if attempt_username_data.is_username_auth_blocked:
        _log.info(create_authentication_log_message(
            'attempt',
            f'[{attempt_username_data.user.username}] account is blocked until '
            f'{attempt_username_data.username_unlock_time}',
            ip_address))
        attempt_username_data.save()
        return False, gettext_lazy('Authentication for this user is blocked. Please contact administrator')
    if login_successful:
        if attempt_username_data.failed_login_attempts == 0:
            _log.info(create_authentication_log_message(
                'attempt', f'[{attempt_username_data.user.username}] has been successfully authenticated',
                ip_address))
            attempt_username_data.save()
            return True, None
        else:
            _log.info(create_authentication_log_message(
                'attempt',
                f'[{attempt_username_data.user.username}] has been successfully authenticated after '
                f'{attempt_username_data.failed_login_attempts} '
                f'tries. Failed login attempts counter has been reset',
                ip_address))
            attempt_username_data.failed_login_attempts = 0
            attempt_username_data.save()
            return True, None
    else:
        # Get authentication settings
        auth_settings = ConsoleAuthSettings.get_solo()
        _log.info(create_authentication_log_message(
            'attempt',
            f'[{attempt_username_data.user.username}] failed to authenticate. Amount of failed attempts: '
            f'{attempt_username_data.failed_login_attempts + 1}/{auth_settings.login_attempts_limit}',
            ip_address))
        amount_of_failed_attempts = attempt_username_data.failed_login_attempts + 1
        attempt_username_data.failed_login_attempts += 1

        if (auth_settings.login_attempts_limit > 0 and
                amount_of_failed_attempts == auth_settings.login_attempts_limit and
                attempt_username_data.is_username_auth_blocked == False):

            attempt_username_data.is_username_auth_blocked = True
            user_unlock_time = dtnow() + auth_settings.login_block_timeout
            _log.info(create_authentication_log_message(
                'settings',
                f'[{attempt_username_data.user.username}] Blocked authentication for '
                f'{attempt_username_data.user.username} until {user_unlock_time} '
                f'due to the exceeding the limit of login attempts',
                ip_address))
            attempt_username_data.username_unlock_time = user_unlock_time
            attempt_username_data.save()
            return False, gettext_lazy('Authentication for this user is blocked for {time}').format(
                time=auth_settings.login_block_timeout)
        elif attempt_username_data.is_username_auth_blocked:
            _log.info(create_authentication_log_message(
                'attempt',
                f'[{attempt_username_data.user.username}] failed to authenticate due to timeout. '
                f'Amount of failed attempts: '
                f'{attempt_username_data.failed_login_attempts + 1}/{auth_settings.login_attempts_limit}',
                ip_address))
            return False, gettext_lazy(
                "Authentication for this user is blocked, please contact system administrator"),
        attempt_username_data.save()
        return False, gettext_lazy('Please enter a correct username and password. '
                                   'Note that both fields may be case-sensitive.')


def get_timeout_formatted(console_auth_settings):
    """ Method for formatting DurationField into dict with corresponding time values
    :return: dictionary with the following content:
        {
            'days': <days_integer>,
            'hours': <hours_integer>,
            'minutes': <minutes_integer>,
            'seconds': <seconds_integer>
        }
    """
    formatted_timeout = {'days': console_auth_settings.login_block_timeout.days}
    formatted_timeout['hours'], rem = divmod(console_auth_settings.login_block_timeout.seconds, 3600)
    formatted_timeout["minutes"], formatted_timeout["seconds"] = divmod(rem, 60)
    return formatted_timeout


def set_account_block(auth_data):  # todo not used. remove?
    """ Method for forbieden access to authentication for user account """
    auth_data.is_username_auth_blocked = True
    _log.info(create_authentication_log_message(
        'settings', f'user [{auth_data.user.username}] has been blocked by Administrator'))
    auth_data.save()
