from parallels.core.logging import get_logger
from parallels.core.actions.base.common_action import CommonAction
from parallels.core.actions.utils.logging_properties import LoggingProperties
from parallels.core.reports.model.issue import Issue
from parallels.core.utils.common import format_list
from parallels.plesk import messages
from parallels.plesk.utils.plesk_components import get_installed_components

logger = get_logger(__name__)


class RemoveMissingComponents(CommonAction):
    """Remove missing Perl/Python components from backup dump

    We need to perform such check because:
    1) On Windows, Since Plesk 12.5 Perl and Python can not be installed automatically via Plesk autoinstaller
    due to the license reasons. On Unix, Python can not be installed and used on fresh OSes too.
    2) It is common to have Perl/Python enabled on old source servers for practically every subscription,
    even if it does not actually use it. Actually the issue should affect only small amount of domains.
    3) Plesk restore for hosting settings emits and *error* message for *every* domain with Perl/Python enabled.
    4) Plesk restore for APS applications also report the issue.
    4) Capability checks report the issue too.

    So, to avoid many error messages (for every subscription - 2 for hosting settings restoration,
    2 for APS applications, 2 for capability checks) in migration and pre-migration reports,
    we control this situation ourselves, without Plesk restore and Plesk capability checker.

    See also:
    parallels.plesk.actions.hosting_settings.check.check_missing_components.CheckMissingComponents
    """

    def get_description(self):
        return messages.REMOVE_MISSING_COMPONENTS_DESCRIPTION

    def get_failure_message(self, global_context):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        """
        return messages.REMOVE_MISSING_COMPONENTS_FAILURE

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

        If action is critical and it failed, migration tool completely stops.
        Otherwise it proceeds to the next steps of migrations.

        This action affects only error reporting, so it is not critical, always return False.

        :rtype: bool
        """
        return False

    def get_logging_properties(self):
        return LoggingProperties(info_log=False)

    def run(self, global_context):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        """
        for component, installed in get_installed_components(global_context.conn.target.plesk_server).items():
            if component in {'perl', 'python'} and not installed:
                domains = self.get_domains_with_component(global_context, component)
                # Disable scripting option in backup dump
                for domain in domains:
                    domain.scripting.disable_option(component)

                # As pre-migration report's common issues are not added automatically to final migration report,
                # report the issue to 'safe' object
                if len(domains) > 0:
                    global_context.safe.fail_general(
                        messages.MISSING_COMPONENT_ISSUE.format(
                            component=component, domains=format_list([d.name for d in domains])
                        ),
                        messages.MISSING_COMPONENT_SOLUTION,
                        Issue.SEVERITY_WARNING
                    )

    @staticmethod
    def get_domains_with_component(global_context, component):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type component: str
        :rtype: list
        """
        domains = []
        for subscription in global_context.iter_all_subscriptions():
            for domain in subscription.converted_dump.iter_domains():
                if domain.scripting is not None and domain.scripting.is_option_enabled(component):
                    domains.append(domain)
        return domains