from parallels.core.logging import get_logger
from parallels.core.runners.base import BaseRunner
from parallels.core.utils.paths.converters.unix.source import UnixSourceWebPathConverter
from parallels.core.utils.paths.converters.unix.target import UnixTargetWebPathConverter
from parallels.core.utils.paths import web_paths
from parallels.core.utils.paths.hosting_description_web_files import HostingDescriptionWebFiles
from parallels.plesk.source.custom import messages
from parallels.core.actions.base.subscription_action import SubscriptionAction

logger = get_logger(__name__)


class CustomPanelCopyUnixWebContentLocal(SubscriptionAction):
    """Put Unix web files that are already on target server to correct locations

    This action is applicable when access to the server was not provided in configuration file, and customer
    has already copied files from the source server to the target server
    """

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

        :rtype: str
        """
        return messages.ACTION_COPY_LOCAL_WEB_FILES

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

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        """
        return messages.FAIL_TO_COPY_LOCAL_WEB_FILES

    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.plesk.source.custom.migrated_subscription.CustomPanelMigratedSubscription
        """
        # skip this action for subscription w/o web or is for windows subscriptions
        if subscription.web_target_server is None or subscription.web_target_server.is_windows():
            return False

        return (
            global_context.conn.has_hosting_description_config(subscription.model.source)
            and
            # source web server is not specified, we don't have access to it, so
            # if customer has specified some files to copy, we consider that they all are already
            # on the target server
            subscription.web_source_server is None
            and
            subscription.web_target_server is not None
        )

    def run(self, global_context, subscription):
        """Run action on given subscription

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.plesk.source.custom.migrated_subscription.CustomPanelMigratedSubscription
        """
        files = HostingDescriptionWebFiles().list_files_to_copy(global_context, subscription)
        server = subscription.web_target_server
        for item in files:
            source_path = UnixSourceWebPathConverter().expand(item.source_path, server).rstrip('/') + '/'
            target_path = UnixTargetWebPathConverter().expand(item.target_path, server)
            with server.runner() as runner:
                assert isinstance(runner, BaseRunner)

                command = "/usr/bin/rsync --archive --timeout=30"
                arguments = {}
                for arg_num, exclude in enumerate(item.exclude):
                    exclude_var = 'exclude_%s' % arg_num
                    command += ' --exclude={%s}' % exclude_var
                    arguments[exclude_var] = exclude

                command += ' {source_path} {target_path}'
                arguments.update(dict(
                    source_path=source_path,
                    target_path=target_path
                ))

                runner.execute_command(command, arguments)

                # For files in document root, automatically change permissions, so site works and could be changed
                # For other files that is not implemented. Check http://kb.odin.com/en/6572 for details on
                # how to change the permissions if they are wrong.
                if (
                    isinstance(item.target_path, (web_paths.WebspaceDocumentRoot or web_paths.SiteDocumentRoot)) and
                    subscription.converted_dump.phosting_sysuser_name is not None
                ):
                    runner.execute_command('chown -R {user}:{group} {path}', dict(
                        user=subscription.converted_dump.phosting_sysuser_name,
                        group='psacln',
                        path=target_path
                    ))
                    runner.execute_command('chgrp {group} {path}', dict(
                        group='psaserv',
                        path=target_path
                    ))
