from parallels.core import messages
from parallels.core.actions.base.subscription_action import SubscriptionAction
from parallels.core.actions.post_migration_checks.utils import should_run_post_migration_checks
from parallels.core.dump.entity.password import password_is_empty
from parallels.core.hosting_check.run_checks import run_entities
from parallels.core.logging import get_logger
from parallels.hosting_check import User, DomainMailService

logger = get_logger(__name__)


class TestMailAction(SubscriptionAction):
    def get_description(self):
        """Get short description of action as string

        :rtype: str | unicode
        """
        return messages.ACTION_TEST_MAIL_DESCRIPTION

    def get_failure_message(self, global_context, subscription):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        :rtype: str | unicode
        """
        return messages.ACTION_TEST_MAIL_FAILURE

    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 filter_subscription(self, global_context, subscription):
        """Check if we should run this action on given subscription or not

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        :rtype: bool
        """
        return should_run_post_migration_checks(global_context, 'mail')

    def run(self, global_context, subscription):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        """
        if subscription.mail_converted_dump is None:
            logger.debug(
                messages.SUBSCRIPTION_S_IS_NOT_PRESENTED_MAIL,
                subscription.name
            )
            return

        if not subscription.mail_converted_dump.is_enabled:
            logger.debug(messages.SKIPPED_CHECKING_MAILBOXES_SUBSCRIPTION_S_BECAUSE, subscription.name)
            return

        if (
            subscription.mail_converted_dump.mailsystem is None or
            not subscription.mail_converted_dump.mailsystem.enabled
        ):
            logger.debug(messages.SKIPPED_CHECKING_MAILBOXES_SUBSCRIPTION_S_BECAUSE_1, subscription.name)
            return

        subscription_report = subscription.get_report(global_context.post_migration_check_report_writer)
        for domain in subscription.mail_converted_dump.iter_domains():
            mail_domain_report = subscription_report.subtarget(u'Mail domain', domain.name)
            mail_domain_entities = self._get_mail_domain_check_entities(global_context, subscription, domain.name)
            run_entities(global_context, mail_domain_entities, mail_domain_report)

    @staticmethod
    def _get_mail_domain_check_entities(global_context, subscription, domain_name):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        :type domain_name: str | unicode
        """
        raw_domain = subscription.mail_raw_dump.get_domain(domain_name)
        converted_domain = subscription.mail_converted_dump.get_domain(domain_name)

        result = []

        if not converted_domain.is_enabled:
            logger.debug(messages.SKIPPED_CHECKING_MAIL_SERVICE_DOMAIN_S, domain_name)
            return result

        def get_backup_users(backup_domain):
            return [
                User(mailbox.full_name, mailbox.password.password_text)
                for mailbox in backup_domain.iter_mailboxes()
                if (
                    mailbox.enabled and
                    not password_is_empty(mailbox.password) and
                    mailbox.password.password_type == 'plain'
                )
            ]

        source_users = get_backup_users(raw_domain)
        target_users = get_backup_users(converted_domain)
        target_panel_mail_users = [
            account.short_name for account in global_context.hosting_repository.mail_account.get_list_by_domain(
                subscription.name, domain_name
            )
        ]

        domain_to_check = DomainMailService(
            domain_name=domain_name,
            source_mail_server_ip=subscription.source_mail_ip,
            mail_server_ip=subscription.target_mail_ip or subscription.target_mail_ipv6,
            users=target_users,
            source_users=source_users,
            target_panel_mail_users=target_panel_mail_users
        )

        result.append(domain_to_check)
        return result
