from parallels.core import messages
from parallels.core.actions.base.subscription_backup_action import SubscriptionBackupAction
from parallels.core.actions.utils.logging_properties import LoggingProperties
from parallels.core.reports.model.issue import Issue


class FixProtectedDirUserLogin(SubscriptionBackupAction):
    """Fix logins of protected directory users so they conform to target Plesk rules

    Target Plesk has several requirements for logins of protected directory users. But on source
    panels requirements may be less strong, so in source panel you could create protected
    directory user that you can not create on target Plesk. Here we change logins of such users.
    """
    def get_description(self):
        """Get short description of action as string

        :rtype: str
        """
        return messages.ACTION_FIX_PROTECTED_DIRECTORY_LOGINS_DESCRIPTION

    def get_failure_message(self, global_context, subscription):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        """
        return messages.ACTION_FIX_PROTECTED_DIRECTORY_LOGINS_FAILURE

    def is_critical(self):
        """If action is critical or not.

        If action is critical and it failed for a subscription, migration tool
        won't run the next operations for the subscription.

        :rtype: bool
        """
        return False

    def get_logging_properties(self):
        """Get how action should be logged to migration tools end-user

        :rtype: parallels.core.actions.utils.logging_properties.LoggingProperties
        """
        return LoggingProperties(info_log=False)

    def _run_subscription_backup(
        self, global_context, subscription, subscription_backup
    ):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        """
        for domain in subscription.converted_dump.iter_domains():
            for directory in domain.iter_protected_dirs():
                for user in directory.iter_users():
                    new_user_name = self._fix_user_login(user.name)
                    if user.name != new_user_name:
                        global_context.safe.fail_subscription(
                            subscription.name, messages.PROTECTED_DIRECTORY_LOGIN_FIXED.format(
                                domain=domain.name, directory=directory.name,
                                old_login=user.name, new_login=new_user_name,
                            ), is_critical=False, severity=Issue.SEVERITY_WARNING, omit_logging=True
                        )
                        user.name = new_user_name

    @staticmethod
    def _fix_user_login(user_login):
        """Fix login of protected directory user according to Plesk rules

        Rules for protected directory user login according to Plesk:
        - it must be no longer than 20 alphanumeric characters or "_"/"-".
        - it can also contain the dash symbol ("-"), but cannot start with it
        - it can also contain dot symbol (".").

        Limitations of this method:
        1. We do not check if resulting login is unique for the directory.
        2. We do not check minimum length - empty logins are skipped as is

        :type user_login: str | unicode
        :rtype: str | unicode
        """
        if len(user_login) > 0 and user_login[0] == '-':
            user_login = 'a%s' % user_login[1:]
        user_login = "".join([c if (c.isalnum() or c == '_' or c == '-' or c == '.') else '_' for c in user_login])

        return user_login[:32]
