import posixpath

from parallels.core.runners.base import BaseRunner
from parallels.core.utils.paths.web_files import BaseWebFiles
from parallels.plesk.source.confixx import messages
from parallels.core.utils.paths.copy_web_content import CopyWebContentItem
from parallels.core.utils.paths import web_paths
from parallels.core.utils import plesk_utils


class ConfixxWebFiles(BaseWebFiles):
    """List web files and directories to be copied from custom panel"""

    def list_files_to_copy(self, global_context, subscription):
        """Make a list of source server directories and files to be transferred.

        Confixx content directories:

        Domain root directory of user webN:
            '/srv/www/htdocs/webN/html'
        Web statistics (webalizer):
            '/srv/www/htdocs/confixx/html/webalizer/webN'
        Web statistics (awstats):
            '/srv/www/htdocs/confixx/awstats/webN'
        Apache log files:
            '/srv/www/htdocs/webN/log'

        :type global_context: parallels.plesk.source.confixx.global_context.ConfixxGlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        :rtype: list[parallels.core.utils.paths.copy_web_content.CopyWebContentItem]
        """
        vhosts_dir = global_context.confixx_configuration.get_vhosts_dir()
        source_vhost_name = subscription.raw_dump.owner_login
        tocopy = [
            CopyWebContentItem(
                source_path=web_paths.AbsolutePath(posixpath.join(vhosts_dir, source_vhost_name, 'html')),
                target_path=web_paths.WebspaceDocumentRoot(subscription.converted_dump),
                exclude=self._get_document_root_file_excludes(global_context, subscription)
            ),
            CopyWebContentItem(
                source_path=web_paths.AbsolutePath(posixpath.join(vhosts_dir, source_vhost_name, 'files')),
                target_path=web_paths.WebspacePathTemplate(subscription.converted_dump, "{webspace_root}/files"),
                skip_if_source_not_exists=True
            ),
            # Put Confixx logs to a separate directory, as in Confixx we have one Apache access
            # log for all domains of a customer.
            # In Plesk we have separate logs for each domain. So,
            # if we put logs to the same location, it could break statistics tools.
            # Also, if we put Confixx logs to Plesk logs directory, we will need an
            # action to make correct hardlinks.
            CopyWebContentItem(
                source_path=web_paths.AbsolutePath(posixpath.join(vhosts_dir, source_vhost_name, "log")),
                target_path=web_paths.WebspacePathTemplate(
                    subscription.converted_dump, "{webspace_root}/confixx_logs"
                ),
                skip_if_source_not_exists=True,
                fix_application_paths=False,
            ),
        ]

        for site in subscription.raw_dump.iter_sites():
            site_vhost_name = plesk_utils.convert_wildcard_to_path(
                site.name.encode('idna')
            )

            # site logs
            tocopy.extend([
                CopyWebContentItem(
                    source_path=web_paths.AbsolutePath(posixpath.join(vhosts_dir, site_vhost_name, 'log')),
                    target_path=web_paths.SiteLogs(subscription.converted_dump, site),
                    skip_if_source_not_exists=True,
                    fix_application_paths=False,
                ),
            ])

        return tocopy

    @staticmethod
    def _get_document_root_file_excludes(global_context, subscription):
        """Exclude files that are mapped to document root directory

        If we try copy such files, rsync will fail with error like:
        cannot delete non-empty directory: dir/file.html

        Such situation can happen on Confixx, when customer specified file (not a directory) as
        document root of a site.

        :type global_context: parallels.plesk.source.confixx.global_context.ConfixxGlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        :rtype: list[str | unicode]
        """
        excludes = []
        vhosts_dir = global_context.confixx_configuration.get_vhosts_dir()

        for domain in subscription.converted_dump.iter_domains():
            source_vhost_name = subscription.raw_dump.owner_login

            if domain.www_root is None or subscription.converted_dump.www_root is None:
                continue

            if not domain.www_root.startswith(subscription.converted_dump.www_root):
                continue

            domain_src_doc_root_relative = domain.www_root[len(subscription.converted_dump.www_root)+1:]
            domain_src_doc_root_absolute = posixpath.join(
                vhosts_dir, source_vhost_name, 'html', domain_src_doc_root_relative
            )

            with global_context.conn.confixx.runner() as runner:
                assert isinstance(runner, BaseRunner)
                if (
                    runner.file_exists(domain_src_doc_root_absolute) and
                    not runner.is_dir(domain_src_doc_root_absolute)
                ):
                    excludes.append('/' + domain_src_doc_root_relative)
                    global_context.safe.fail_subscription(
                        subscription.name,
                        messages.SOURCE_DOCUMENT_ROOT_FILE.format(
                            site=domain.name, full_path=domain_src_doc_root_absolute,
                            target_document_root=domain.www_root
                        ),
                        is_critical=False
                    )

        return excludes
