import posixpath
import re

from parallels.core.logging import get_logger
from parallels.core.runners.base import BaseRunner
from parallels.plesk.source.plesk import messages
from parallels.core.actions.base.subscription_action import SubscriptionAction
from parallels.core.utils.common import replace_str_prefix
from parallels.core.utils import subscription_filter
from parallels.core.utils import plesk_utils
from parallels.plesk.source.plesk.server import PleskSourceServer

logger = get_logger(__name__)


class FixUnixPermissions(SubscriptionAction):
    """Fix file ownership for files in domain directory after moving.
    
    If two source panels contain subscriptions with same system user names,
    rename one of users. After content migration, chown directories
    and files for renamed system user.
    """
    def get_description(self):
        return messages.ACTION_FIX_UNIX_PERMISSIONS_DESCRIPTION

    def get_failure_message(self, global_context, subscription):
        return messages.ACTION_FIX_UNIX_PERMISSIONS_FAILED % subscription.name

    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):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        """
        return subscription_filter.unix_with_virtual_hosting(
            subscription
        )

    def run(self, global_context, subscription):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        """
        source_sysuser_name = subscription.raw_dump.get_phosting_sysuser_name()
        sysuser_name = subscription.converted_dump.get_phosting_sysuser_name()
        source_web_server = subscription.web_source_server

        if isinstance(source_web_server, PleskSourceServer):
            vhost_name = subscription.name_idn
            if subscription.web_target_server.get_plesk_version()[:2] >= (17, 9):
                vhost_name = vhost_name.lower()
            target_vhost_dir = posixpath.join(
                subscription.web_target_server.vhosts_dir,
                vhost_name
            )
            if sysuser_name is not None and source_sysuser_name != sysuser_name:
                logger.debug(messages.LOG_FIX_FILE_OWNERSHIP_AFTER_MOVING)
                with subscription.web_source_server.runner() as runner_source:
                    assert isinstance(runner_source, BaseRunner)
                    source_vhost_dir = source_web_server.get_vhost_dir(subscription.name)
                    owner_file_string = runner_source.execute_command(
                        r"/usr/bin/find {source_vhost_dir} -printf '%u:%p\0'", dict(source_vhost_dir=source_vhost_dir)
                    ).stdout
                owner_file_list = filter(None, owner_file_string.split('\0'))
                for line in owner_file_list:
                    regex = re.compile("^(.+):(.+)$")
                    search_result = regex.findall(line)
                    if len(search_result) != 0:
                        (owner, file_path) = search_result[0]
                        if owner == source_sysuser_name:
                            with subscription.web_target_server.runner() as runner_target:
                                assert isinstance(runner_target, BaseRunner)
                                runner_target.execute_command(
                                    "/bin/chown {sysuser_name} {path}", dict(
                                        sysuser_name=sysuser_name,
                                        path=replace_str_prefix(
                                            file_path, source_vhost_dir, target_vhost_dir
                                        )
                                    )
                                )

            with subscription.web_target_server.runner() as runner_target:
                for site in subscription.converted_dump.iter_domains():
                    site_vhost_name = plesk_utils.convert_wildcard_to_path(site.name.encode('idna'))
                    self._fix_pd_owner(runner_target, subscription.web_target_server.vhosts_dir, site_vhost_name)

    @staticmethod
    def _fix_pd_owner(runner_target, vhosts_dir, site_vhost_name):
        """
        :type runner_target: parallels.core.runners.base.BaseRunner 
        """
        pd_path = posixpath.join(
            vhosts_dir, 'system', site_vhost_name, 'pd'
        )
        if runner_target.file_exists(pd_path):
            runner_target.execute_command("/bin/chown -R root:psaserv {pd_path}", dict(pd_path=pd_path))
            runner_target.execute_command("/bin/chmod -R 640 {pd_path}/", dict(pd_path=pd_path))
            runner_target.execute_command("/bin/chmod 710 {pd_path}", dict(pd_path=pd_path))
