from parallels.core.logging import get_logger
from parallels.core.reports.model.issue import Issue
from parallels.core.reports.utils import log_issues
from parallels.plesk.source.web import messages
from parallels.plesk.source.web.actions.base.site_migration import SiteMigrationAction

logger = get_logger(__name__)


# noinspection PyAbstractClass
class ApplicationAction(SiteMigrationAction):
    """Base action for migrated applications
    """

    def filter_action(self, global_context):
        """Check whether we should run this action or not. By default True - action should be executed.

        :type global_context: parallels.plesk.source.web.global_context.WebGlobalMigrationContext
        :rtype: bool
        """
        for application in global_context.list_migrated_applications():
            if self.filter_for_application(global_context, application):
                return True

        return False

    def run(self, global_context):
        """Run action

        :type global_context: parallels.plesk.source.web.global_context.WebGlobalMigrationContext
        :rtype: None
        """
        severity = self.get_failure_severity_for_application()
        action = self.__class__

        for application in global_context.list_migrated_applications():
            safe_object = global_context.site_objects_safe.get_application(application)

            if not self.filter_for_application(global_context, application):
                continue

            if not all(safe_object.is_action_successful(a) for a in self.get_pre_requirement_actions()):
                logger.finfo(messages.LOG_SKIP_EXECUTE_FOR_OBJECT, object_description=application.description())
                continue

            logger.finfo(messages.LOG_EXECUTE_FOR_OBJECT, object_description=application.description())

            failure_message = self.get_failure_message_for_application(global_context, application)
            if failure_message is None:
                failure_message = self.get_failure_message(global_context)

            with safe_object.try_safe(failure_message, severity, action=action):
                issues = self.run_for_application(global_context, application)
                log_issues(issues)
                if issues is not None:
                    safe_object.add_issues(issues, storage_issues_type=self.get_storage_issue_type(), action=action)

            safe_object.set_executed(action)

    def get_failure_message_for_application(self, global_context, application):
        """Get message for situation when action failed for specific application

        :type global_context: parallels.plesk.source.web.global_context.WebGlobalMigrationContext
        :type application: parallels.plesk.source.web.migrated_application.MigratedApplication
        :rtype: str | unicode | None
        """
        return None

    def get_failure_severity_for_application(self):
        """Get issue severity for application in case if that action failed

        :rtype: str | unicode
        """
        return Issue.SEVERITY_ERROR

    def filter_for_application(self, global_context, application):
        """Check whether we should run this action for application or not. By default True - action should be executed.

        :type global_context: parallels.plesk.source.web.global_context.WebGlobalMigrationContext
        :type application: parallels.plesk.source.web.migrated_application.MigratedApplication
        :rtype: None
        """
        return True

    def run_for_application(self, global_context, application):
        """Run action for single migrated application

        :type global_context: parallels.plesk.source.web.global_context.WebGlobalMigrationContext
        :type application: parallels.plesk.source.web.migrated_application.MigratedApplication
        :rtype: list[parallels.core.reports.model.issue.Issue] | None
        """
        raise NotImplementedError()
