from parallels.core.logging import get_logger
from parallels.core.actions.base.subscription_action import SubscriptionAction
from parallels.core.migrator_config import is_transfer_resource_limits_enabled
from parallels.core.reports.model.issue import Issue
from parallels.core.utils.common import safe_string_repr
from parallels.core.utils.restore_hosting_utils import restore_hosting_settings_lock
from parallels.plesk import messages
from parallels.plesk.hosting_repository.subscription import SubscriptionCannotBeSyncedWithPlan

logger = get_logger(__name__)


class SyncSubscriptionPlan(SubscriptionAction):
    """Synchronize subscriptions with service plans

    We have 2 ways controlled by 'transfer-resource-limits' option in config.ini:
    1) Transfer limits and permissions.
    2) Use limits and permissions from service plan.

    In the 2nd case we should keep subscriptions synced with service plans.
    But Plesk restore resets sync status of subscription when restoring
    backup without plan reference (which is removed for other reasons
    at _remove_subscriptions_to_plans_relation function), making each
    restored subscription locked. So we have to call sync in explicit way.
    (actually there is another way to resolve the problem
    - fill Plesk backup with correct plan information, but that way is
    a bit more complex)

    In the 1st case there is no sense to keep synced status, as limits
    and permissions of each subscription are taken from the source panel,
    not from new Plesk service template.
    """

    def get_description(self):
        return messages.SYNC_SUBSCRIPTION_WITH_PLAN

    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.FAILED_TO_SYNC_SUBSCRIPTION_WITH_PLAN

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

    def run(self, global_context, subscription):
        """Run action on given subscription

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        :rtype: None
        """
        transfer_resource_limits = is_transfer_resource_limits_enabled(
            global_context.config,
            global_context.target_panel_obj
        )

        is_custom = subscription.model.plan_name is None
        is_locked = subscription.raw_dump.locked
        if not is_custom and (not is_locked or not transfer_resource_limits):
            try:
                with restore_hosting_settings_lock:
                    global_context.hosting_repository.subscription.sync(subscription.name)
            except SubscriptionCannotBeSyncedWithPlan as e:
                logger.exception()
                global_context.safe.fail_subscription(
                    subscription.name, safe_string_repr(e), is_critical=False, omit_logging=True,
                    severity=Issue.SEVERITY_WARNING
                )
