from parallels.core.utils.common import unused, generate_random_password, cached, join_nonempty_strs
from parallels.plesk.hosting_repository.utils.cli.base import BaseCli
from parallels.plesk.hosting_repository.utils.cli.utils import add_password_env


class SubscriptionCreateCli(BaseCli):
    def __init__(
        self, runner, subscription_name, subscription_username, is_enable_hosting, ips,
        owner_username=None,
        service_plan_name=None,
        admin_description=None,
        reseller_description=None,
        guid=None,
        creation_date=None,
        mail_service=None
    ):
        super(SubscriptionCreateCli, self).__init__(runner)
        self._subscription_name = subscription_name
        self._subscription_username = subscription_username
        self._is_enable_hosting = is_enable_hosting
        self._ips = ips
        self._owner_username = owner_username
        self._service_plan_name = service_plan_name
        self._admin_description = admin_description
        self._reseller_description = reseller_description
        self._guid = guid
        self._creation_date = creation_date
        self._mail_service = mail_service

    @property
    def name(self):
        return 'subscription'

    def _get_args(self):
        ips_str = join_nonempty_strs(self._ips, ',')
        args = [
            '--create', self._subscription_name,
            '-hosting', 'true' if self._is_enable_hosting else 'false',
            '-hst_type', 'phys',
            '-login', self._subscription_username,
            '-passwd', '',
            '-ip', ips_str,
            '-do-not-apply-skeleton',
            '-notify', 'false'
        ]

        if self._owner_username is not None:
            args.extend(['-owner', self._owner_username])

        if self._service_plan_name is not None:
            args.extend(['-service_plan', self._service_plan_name, '-force'])

        if self._admin_description is not None:
            args.extend(['-admin-description', self._admin_description])

        if self._reseller_description is not None:
            args.extend(['-reseller-description', self._reseller_description])

        if self._guid:
            args.extend(['-guid', self._guid])

        if self._creation_date:
            args.extend(['-creation-date', self._creation_date])

        if self._mail_service is not None:
            args.extend(['-mail_service', str(self._mail_service).lower()])

        return args

    def _get_env(self):
        return add_password_env({}, _generate_password(self._subscription_name), 'plain')


class SubscriptionEnableHostingCli(BaseCli):
    def __init__(self, runner, subscription_name, username, ips):
        """Construct command to enable virtual hosting on subscription with given name in Plesk via CLI

        :type runner: parallels.core.utils.plesk_cli_runner.PleskCLIRunnerBase
        :type subscription_name: str
        :type username: str
        :type ips: list[str]
        """
        super(SubscriptionEnableHostingCli, self).__init__(runner)
        self._subscription_name = subscription_name
        self._username = username
        self._ips = ips

    @property
    def name(self):
        return 'subscription'

    def _get_args(self):
        ips_str = join_nonempty_strs(self._ips, ',')
        return [
            '--update', self._subscription_name,
            '-hosting', 'true',
            '-hst_type', 'phys',
            '-login', self._username,
            '-passwd', '',
            '-ip', ips_str,
            '-do-not-apply-skeleton'
        ]

    def _get_env(self):
        return add_password_env({}, _generate_password(self._subscription_name), 'plain')


class SubscriptionSetOwnerCli(BaseCli):
    def __init__(self, runner, subscription_name, owner_username):
        """Construct command to set owner of subscription with given name in Plesk via CLI

        :type runner: parallels.core.utils.plesk_cli_runner.PleskCLIRunnerBase
        :type subscription_name: str
        :type owner_username: str
        """
        super(SubscriptionSetOwnerCli, self).__init__(runner)
        self._subscription_name = subscription_name
        self._owner_username = owner_username

    @property
    def name(self):
        return 'subscription'

    def _get_args(self):
        return [
            '--update', self._subscription_name,
            '-owner', self._owner_username
        ]


class SubscriptionAddServicePlan(BaseCli):
    def __init__(self, runner, subscription_name, service_plan_name):
        super(SubscriptionAddServicePlan, self).__init__(runner)
        self._subscription_name = subscription_name
        self._service_plan_name = service_plan_name

    @property
    def name(self):
        return 'subscription'

    def _get_args(self):
        return [
            '--add-subscription', self._subscription_name,
            '-service-plan', self._service_plan_name,
            '-force'
        ]


class SubscriptionSyncCli(BaseCli):
    def __init__(self, runner, subscription_name):
        super(SubscriptionSyncCli, self).__init__(runner)
        self._subscription_name = subscription_name

    @property
    def name(self):
        return 'subscription'

    def _get_args(self):
        return [
            '--sync-subscription', self._subscription_name,
            '-force'
        ]


class SubscriptionSettingsUpdateCli(BaseCli):
    def __init__(
        self, runner, subscription_name,
        max_domains=None, max_subdomains=None, max_domain_aliases=None, max_databases=None, max_mssql_databases=None,
        max_mail_accounts=None
    ):
        super(SubscriptionSettingsUpdateCli, self).__init__(runner)
        self._subscription_name = subscription_name
        self._max_domains = max_domains
        self._max_subdomains = max_subdomains
        self._max_domain_aliases = max_domain_aliases
        self._max_databases = max_databases
        self._max_mssql_databases = max_mssql_databases
        self._max_mail_accounts = max_mail_accounts

    @property
    def name(self):
        return 'subscription_settings'

    def _get_args(self):
        args = [
            '--update', self._subscription_name
        ]
        args.extend(self._get_limit_args())
        return args

    def _get_limit_args(self):
        args = []
        if self._max_domains is not None:
            args.extend(['-max_site', self._max_domains])
        if self._max_subdomains is not None:
            args.extend(['-max_subdom', self._max_subdomains])
        if self._max_domain_aliases is not None:
            args.extend(['-max_dom_aliases', self._max_domain_aliases])
        if self._max_databases is not None:
            args.extend(['-max_db', self._max_databases])
        if self._max_mssql_databases is not None:
            args.extend(['-max_mssql_db', self._max_mssql_databases])
        if self._max_mail_accounts is not None:
            args.extend(['-max_box', self._max_mail_accounts])
        return args

    def _is_useless(self):
        return len(self._get_limit_args()) == 0


class SubscriptionExternalIdCli(BaseCli):
    def __init__(self, runner, subscription_name, external_id):
        super(SubscriptionExternalIdCli, self).__init__(runner)
        self._subscription_name = subscription_name
        self._external_id = external_id

    @property
    def name(self):
        return 'subscription'

    def _get_args(self):
        return [
            '--update', self._subscription_name,
            '-external-id', self._external_id
        ]


class SubscriptionRemoveCli(BaseCli):
    def __init__(self, runner, subscription_name):
        """
        :type runner: parallels.core.utils.plesk_cli_runner.PleskCLIRunnerBase
        :type subscription_name: str | unicode
        """
        super(SubscriptionRemoveCli, self).__init__(runner)
        self._subscription_name = subscription_name

    @property
    def name(self):
        return 'subscription'

    def _get_args(self):
        return [
            '--remove', self._subscription_name
        ]


@cached
def _generate_password(subscription_name):
    """Generate password for subscription, persistent for migration and multiple creation attempts

    :type subscription_name: str
    :rtype: str
    """
    unused(subscription_name)  # use subscription name just as cache key
    return generate_random_password()
