from parallels.core.logging import get_logger
from parallels.core import messages
from parallels.core.actions.base.subscription_action import SubscriptionAction
from parallels.core.actions.utils.logging_properties import LoggingProperties
from parallels.core.registry import Registry
from parallels.core.reports.model.issue import Issue
from parallels.core.reports.model.report import Report
from parallels.core.reports.plain_report import PlainReport
from parallels.core.reports.printer import print_report
from parallels.core.safe import add_report_issues
from parallels.core.utils.migration_progress import SubscriptionMigrationStatus
from parallels.core.utils.subscription_operations import command_name_to_operation

logger = get_logger(__name__)


class PrintSubscriptionStatus(SubscriptionAction):
    def get_description(self):
        return messages.PRINT_SUBSCRIPTION_MIGRATION_STATUS

    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_PRINT_SUBSCRIPTION_MIGRATION_STATUS

    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 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 is_execute_for_failed_subscriptions(self):
        """Whether this action should be executed for completely failed subscription or not

        For example, subscription is completely failed if we failed to create it on the target server.
        Print subscription report should be executed anyway.

        :rtype: bool
        """
        return True

    def run(self, global_context, subscription):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        """
        safe = global_context.safe
        subscription_report = Report('Subscription', subscription.name)

        # add issues from 'Safe'
        if subscription.name in safe.failed_objects.subscriptions:
            add_report_issues(
                subscription_report,
                safe.failed_objects.subscriptions[subscription.name]
            )
        for issue in safe.issues.subscriptions[subscription.name]:
            subscription_report.add_issue_obj(issue)

        # add issues from pre-migration checks
        plain_pre_check_report = PlainReport(
            global_context.pre_check_report, global_context.migration_list_data
        )
        subscription_pre_check_report = plain_pre_check_report.get_subscription_report(subscription.name)
        for issue in subscription_pre_check_report.issues:
            subscription_report.add_issue_obj(issue)

        # if report has no issues - add successful status
        if not subscription_report.has_issues():
            subscription_report.add_issue(
                u'subscription_migr_success', Issue.SEVERITY_INFO,
                messages.SUBSCRIPTION_MIGRATED_SUCCESSFULLY
            )

        # print report
        print_report(
            subscription_report, show_no_issue_branches=False,
            log_message=messages.SUBSCRIPTION_MIGRATION_FINISHED_HERE_IS_STATUS
        )

        # update data:
        # 1) in global subscription state object, necessary for overall statistics
        # 2) in per-session storage to display migration status in GUI
        statistics_subscription_status = global_context.progress.get_subscription(
            subscription.name
        )

        command_name = Registry.get_instance().get_command_name()
        operation = command_name_to_operation(command_name)

        if global_context.subscriptions_status.is_stop(subscription.name):
            per_session_status = SubscriptionMigrationStatus.CANCELLED
        elif not subscription_report.has_errors_or_warnings():
            statistics_subscription_status.status = SubscriptionMigrationStatus.FINISHED_OK
            if command_name == 'undo-dns-forwarding':
                # If undo was successful, set DNS forwarding status to "reverted"
                per_session_status = SubscriptionMigrationStatus.REVERTED
            else:
                per_session_status = SubscriptionMigrationStatus.FINISHED_OK
        elif not subscription_report.has_errors():
            statistics_subscription_status.status = SubscriptionMigrationStatus.FINISHED_WARNINGS
            per_session_status = SubscriptionMigrationStatus.FINISHED_WARNINGS
        else:
            statistics_subscription_status.status = SubscriptionMigrationStatus.FINISHED_ERRORS
            per_session_status = SubscriptionMigrationStatus.FINISHED_ERRORS

        if operation is not None and per_session_status is not None:
            global_context.subscriptions_status.set_operation_status(
                subscription.name, operation, per_session_status
            )
            global_context.subscriptions_report.set_operation_messages(
                subscription.name, operation, [
                    {
                        'severity': issue.severity,
                        'description': issue.get_issue_text()
                    }
                    for issue in subscription_report.issues
                ]
            )
