import posixpath

from parallels.core import messages
from parallels.core.actions.base.subscription_action import SubscriptionAction
from parallels.core.logging import get_logger
from parallels.core.utils import subscription_filter
from parallels.core.utils.paths import web_paths
from parallels.core.utils.paths.converters.unix.target import UnixTargetWebPathConverter

logger = get_logger(__name__)


class FixUnixHtaccess(SubscriptionAction):
    """Fix htaccess files for protected directories

    On some source panels, like cPanel and Confixx, protected directories are controlled by
    '.htaccess' and '.htpasswd' files. Plesk has another way, and these '.htaccess' files
    make protected directories completely inaccessible. So, in this action we remove all options
    related to protected directories from '.htaccess' files.
    """

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

        :rtype: str
        """
        return messages.ACTION_FIX_UNIX_HTACCESS_DESCRIPTION

    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
        :rtype: str | unicode
        """
        return messages.ACTION_FIX_UNIX_HTACCESS_FAILED.format(subscription_name=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):
        """Run action on given subscription

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        """
        for domain in subscription.converted_dump.iter_domains():
            for directory in domain.iter_protected_dirs():
                self._fix_protected_dir_htaccess(
                    subscription.web_target_server, subscription.converted_dump, domain, directory
                )

    @staticmethod
    def _fix_protected_dir_htaccess(target_web_server, subscription, domain, directory):
        """
        Fix '.htaccess' file for single protected directory

        :type directory: parallels.core.dump.data_model.ProtectedDir
        """
        path = posixpath.join(
            UnixTargetWebPathConverter().expand(
                web_paths.SiteDocumentRoot(subscription, domain),
                target_web_server
            ),
            directory.name.lstrip('/'), '.htaccess'
        )
        with target_web_server.runner() as runner:
            if runner.file_exists(path):
                content = []
                modified = False
                for line in runner.get_file_contents(path).splitlines(True):
                    if line.startswith('AuthType') or line.startswith('AuthName') or line.startswith('AuthUserFile'):
                        modified = True
                        continue
                    content.append(line)

                if modified:
                    logger.fdebug(
                        messages.FIX_HTACCESS_FOR_PROTECTED_DIR,
                        filename=path, directory=directory.name, domain=domain.name
                    )
                    runner.upload_file_content(path, ''.join(content))