from parallels.core import get_logger, safe_format
from parallels.core.reports.model.issue import Issue
from parallels.core.utils.common import default
from parallels.core.utils.common_constants import SSH_DEFAULT_PORT
from parallels.core.utils.unix_utils import format_command
from parallels.plesk.source.web.utils.copy_content.linux.ssh_based import CopyContentLinuxSSHBased
from parallels.plesk.source.web import messages


logger = get_logger(__name__)


class CopyContentLinuxScp(CopyContentLinuxSSHBased):
    def copy_folder(self, global_context, folder):
        issues = super(CopyContentLinuxScp, self).copy_folder(global_context, folder)

        # remove migrator agent files after transferring - they are garbage for the target server;
        # we can not exclude them because "scp" does not have any options to exclude files;
        # we can first build tree of files with "ls"/"find" and then copy them one by one,
        # excluding files of web RPC agent, but that could significantly slow down transfer process
        # as we have to launch multiple "scp" processes with multiple "su --shell" calls
        try:
            with folder.target_server.runner() as local_runner:
                local_runner.execute_command(
                    u'su {username} --shell /bin/sh -c {command}', dict(
                        username=folder.target_sysuser_login,
                        command=format_command(
                            u"find {target_dir} -type d -name 'plesk-migrator-agent-*' -exec rm -rf '{{}}' \; -quit",
                            target_dir=folder.target_path.rstrip('/')
                        )
                    ),
                )
        except Exception as e:
            logger.exception()
            issues.append(
                Issue(
                    'failed-to-remove-agent-from-target', Issue.SEVERITY_WARNING,
                    safe_format(
                        messages.ACTION_COPY_FILES_SCP_REMOVE_AGENT_FAILED,
                        target_folder=folder.target_path,
                        reason=e
                    )
                )
            )

        return issues

    def _get_copy_command(
        self, source_host, source_username, source_port, private_ssh_key, source_dir, target_dir, excludes
    ):
        """Get shell command which should be used to copy directories using SSH

        :type source_host: str | unicode
        :type source_username: str | unicode
        :type source_port: int | None
        :type private_ssh_key: str | unicode
        :type source_dir: str | unicode
        :type target_dir: str | unicode
        :type excludes: list[str | unicode]
        :rtype: str | unicode
        """
        return format_command(
            u"scp -r -i {key} -P {port} "
            u"-o PasswordAuthentication=no -o StrictHostKeyChecking=no -o GSSAPIAuthentication=no "
            u"{user}@{host}:{source_dir} {target_dir}",
            key=private_ssh_key,
            port=default(source_port, SSH_DEFAULT_PORT),
            user=source_username,
            host=source_host,
            # Double escape source directory name, for scp and for local shell.
            # "/." means to copy all files in a directory (including hidden ones, if comparing with "/*")
            source_dir=format_command("{source_dir}/.", source_dir=source_dir),
            target_dir=target_dir + '/'
        )

    def get_method_title(self):
        """Get transfer method title as string

        :rtype: str | unicode
        """
        return 'scp'
