from parallels.core import safe_format
from parallels.core.actions.base.common_action import CommonAction
from parallels.core.logging import get_logger
from parallels.core.runners.exceptions.connection_check import ConnectionCheckError
from parallels.core.utils.windows_agent_remote_object import RPCAgentBuilder, RPCAgentConnectionError
from parallels.hosting_check import Severity
from parallels.plesk.source.plesk import messages
from parallels.plesk.source.plesk.connections.source_remote_smarter_mail_server import \
    PleskSourceRemoteSmarterMailServer

logger = get_logger(__name__)


class CheckSourceRemoteSmarterMailAction(CommonAction):
    """Check connections to source remote SmarterMail servers

    To copy mail messages, migrator requires RPC agent to be installed, running and available on that server.
    If it is not installed, then we report that to customer (providing link/path to install RPC agent).
    """

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

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

    def get_failure_message(self, global_context):
        """Get message for situation when action failed

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        """
        return messages.ACTION_CHECK_REMOTE_SMARTER_MAIL_FAILURE

    def run(self, global_context):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        """
        servers = set()

        # Compose list of remote SmarterMail servers
        for subscription in global_context.iter_all_subscriptions():
            if (
                subscription.mail_source_server is not None and
                # mail is located on server other than web server - the only option for Plesk is remote SmarterMail
                subscription.mail_source_server != subscription.web_source_server
            ):
                servers.add(subscription.mail_source_server)

        # Check connection to each server. If connection failed - add issue to pre-migration report.
        for server in servers:
            if isinstance(server, PleskSourceRemoteSmarterMailServer):
                self._check_connection_to_server(global_context, server)

    @staticmethod
    def _check_connection_to_server(global_context, server):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type server: parallels.plesk.source.plesk.connections.source_remote_smarter_mail_server.PleskSourceRemoteSmarterMailServer
        """
        try:
            with server.runner() as runner:
                runner.check(server.ip())
        except (ConnectionCheckError, RPCAgentConnectionError):
            logger.exception()
            rpc_agent_path = RPCAgentBuilder().build()
            global_context.pre_check_report.add_issue(
                'source_smarter_mail_rpc_agent', Severity.ERROR,
                safe_format(
                    messages.REMOTE_SMARTER_MAIL_RPC_AGENT_CONNECTION_ISSUE,
                    ip=server.ip(),
                    rpc_agent_path=rpc_agent_path
                ),
                # Show link to download RPC agent in GUI
                solution_download_rpc_agent=True
            )
