import os
import itertools

from parallels.core import MigrationNoContextError
from parallels.core.logging import get_logger
from parallels.core.migrator_config import read_skip_check_same_webspace
from parallels.core.utils.common import safe_string_repr
from parallels.plesk.connections.target_server import PleskTargetServer
from parallels.plesk.source.web import messages
from parallels.plesk.source.web.actions.base.site_migration import SiteMigrationAction
from parallels.plesk.source.web.utils.status_storage import StatusStorage

logger = get_logger(__name__)


class CheckSameWebspace(SiteMigrationAction):
    """Check if source and target sites (webspaces) are not the same.
     
     That is necessary because:
     1. There is a huge risk to overwrite customer's files
     (for example, FTP migrator makes file empty when destination and source are the same).
     2. In most situations, specifying target site as source one is just a customer's mistake.
     Specifying target site as source one is misuse of site migrator and should be prohibited.
     """

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

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

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

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :rtype: str | unicode
        """
        return messages.ACTION_CHECK_SAME_WEBSPACE_FAILURE

    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.core.global_context.GlobalMigrationContext
        :rtype: bool
        """
        return not read_skip_check_same_webspace(global_context.config)

    def run(self, global_context):
        """
        :type global_context: parallels.plesk.source.web.global_context.WebGlobalMigrationContext
        """
        plesk_server = global_context.conn.target.plesk_server
        assert isinstance(plesk_server, PleskTargetServer)

        # Detect if source and target sites are in the same webspace in the following way:
        # 1. In one of the previous steps we uploaded RPC agent.
        # 2. RPC agent was uploaded to a directory with an unique random name.
        # 3. Look for this name in the target webspace. If there is such name then that the webspaces are the same.

        target_webspace_directory = plesk_server.get_vhost_dir(
            global_context.site_info_storage.get_target_subscription()
        )

        agent_id = global_context.conn.get_source().get_plesk_agent_id()

        try:
            for root, dirs, files in os.walk(target_webspace_directory):
                for name in itertools.chain(dirs, files):
                    if agent_id in name:
                        raise SameWebspaceException(messages.ERROR_MIGRATE_FROM_THE_SAME_WEBSPACE)
        except SameWebspaceException as e:
            global_context.status_storage.set_operation_failure(
                StatusStorage.OPERATION_CONNECT, safe_string_repr(e)
            )
            raise


class SameWebspaceException(MigrationNoContextError):
    pass
