import posixpath

from parallels.core.utils.migrator_utils import path_startswith
from parallels.core.utils.paths import web_paths
from parallels.core.utils.paths.copy_web_content import CopyWebContentItem
from parallels.core.utils.paths.web_files import BaseWebFiles
from parallels.core.utils import plesk_utils
from parallels.core.utils.windows_utils import normalize_path
from parallels.plesk.source.plesk.actions.content.web.utils import list_webuser_security_files, get_main_security_file


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

        :type global_context: parallels.plesk.source.cpanel.global_context.CpanelGlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        :rtype: list[parallels.core.utils.paths.copy_web_content.CopyWebContentItem]
        """
        if subscription.web_target_server.is_windows():
            return PleskWindowsWebFiles().list_files_to_copy(global_context, subscription)
        else:
            return PleskUnixWebFiles().list_files_to_copy(global_context, subscription)


class PleskUnixWebFiles(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.

        :type global_context: parallels.plesk.source.cpanel.global_context.CpanelGlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        :rtype: list[parallels.core.utils.paths.copy_web_content.CopyWebContentItem]
        """
        if subscription.web_source_server.get_plesk_version()[:2] >= (17, 9):
            # since 17.9 vhost_name inside vhosts_dir and system dir is in lower case
            vhost_name = str(subscription.name_idn).lower()
        else:
            vhost_name = str(subscription.name_idn)

        source_vhosts_dir = subscription.web_source_server.vhosts_dir
        www_roots = self._get_site_www_roots(subscription)

        def compose_webspace_root_exclude(lst):
            return ['/%s' % name for name in lst if all(not path_startswith(name, www_root) for www_root in www_roots)]

        # chroot environment must be recreated, not copied.
        # That is necessary because binaries and libraries from old system
        # may be incompatible with target server (for example, other OS or architecture),
        # so customer won't be able to login to the system after moving.
        chroot_excludes = subscription.web_source_server.get_chroot_directories()

        if subscription.web_source_server.plesk_version >= (11, 5):
            # since 11.5 we have a new virtual host structure: each domain is
            # splitted over VHOSTS_D/<domain_name> and
            # VHOSTS_D/system/<domain_name>
            tocopy = [
                CopyWebContentItem(
                    source_path=web_paths.AbsolutePath(posixpath.join(source_vhosts_dir, vhost_name)),
                    target_path=web_paths.WebspaceRoot(subscription.converted_dump),
                    exclude=compose_webspace_root_exclude(['logs', 'conf', 'statistics'] + chroot_excludes),
                ),
                CopyWebContentItem(
                    source_path=web_paths.AbsolutePath(
                        posixpath.join(source_vhosts_dir, "system", vhost_name, "logs")
                    ),
                    target_path=web_paths.WebspaceLogs(subscription.converted_dump),
                    skip_if_source_not_exists=True,
                    fix_application_paths=False,
                ),
                CopyWebContentItem(
                    source_path=web_paths.AbsolutePath(
                        posixpath.join(source_vhosts_dir, "system", vhost_name, "statistics")
                    ),
                    target_path=web_paths.WebspaceStatistics(subscription.converted_dump),
                    skip_if_source_not_exists=True,
                    fix_application_paths=False,
                ),
                CopyWebContentItem(
                    source_path=web_paths.AbsolutePath(
                        posixpath.join(source_vhosts_dir, "system", vhost_name, "pd")
                    ),
                    target_path=web_paths.WebspaceProtectedDirs(subscription.converted_dump),
                    skip_if_source_not_exists=True,
                    fix_application_paths=False,
                ),
            ]
        else:
            tocopy = [
                CopyWebContentItem(
                    source_path=web_paths.AbsolutePath(posixpath.join(source_vhosts_dir, vhost_name)),
                    target_path=web_paths.WebspaceRoot(subscription.converted_dump),
                    exclude=compose_webspace_root_exclude(['logs', 'conf', 'statistics', 'pd'] + chroot_excludes),
                ),
                CopyWebContentItem(
                    source_path=web_paths.AbsolutePath(
                        posixpath.join(source_vhosts_dir, vhost_name, "statistics", "logs")
                    ),
                    target_path=web_paths.WebspaceLogs(subscription.converted_dump),
                    skip_if_source_not_exists=True,
                    fix_application_paths=False,
                ),
                CopyWebContentItem(
                    source_path=web_paths.AbsolutePath(
                        posixpath.join(source_vhosts_dir, vhost_name, "statistics")
                    ),
                    target_path=web_paths.WebspaceStatistics(subscription.converted_dump),
                    exclude=['/logs'],
                    skip_if_source_not_exists=True,
                    fix_application_paths=False,
                ),
                CopyWebContentItem(
                    source_path=web_paths.AbsolutePath(
                        posixpath.join(source_vhosts_dir, vhost_name, "pd")
                    ),
                    target_path=web_paths.WebspaceProtectedDirs(subscription.converted_dump),
                    skip_if_source_not_exists=True,
                    fix_application_paths=False,
                ),
            ]

        for site in subscription.converted_dump.iter_sites():
            # skip sites w/o hosting
            if not site.is_virtual_hosting:
                continue

            if subscription.web_source_server.get_plesk_version()[:2] >= (17, 9):
                # since 17.9 vhost_name inside vhosts_dir and system dir is in lower case
                site_vhost_name = plesk_utils.convert_wildcard_to_path(site.name.encode('idna')).lower()
            else:
                site_vhost_name = plesk_utils.convert_wildcard_to_path(site.name.encode('idna'))

            if subscription.web_source_server.plesk_version >= (10, 0):  # plesk #10.x
                if subscription.web_source_server.plesk_version >= (11, 5):
                    tocopy.append(
                        CopyWebContentItem(
                            source_path=web_paths.AbsolutePath(
                                posixpath.join(source_vhosts_dir, "system", site_vhost_name, "pd")
                            ),
                            target_path=web_paths.SiteProtectedDirs(subscription.converted_dump, site),
                            skip_if_source_not_exists=True,
                            fix_application_paths=False,
                        )
                    )

                    source_logs_subdir = posixpath.join(
                        source_vhosts_dir, "system",
                        site_vhost_name, "logs"
                    )
                    source_statistics_subdir = posixpath.join(
                        source_vhosts_dir, 'system',
                        site_vhost_name, "statistics"
                    )
                    source_statistics_exclude = []
                else:
                    tocopy.append(
                        CopyWebContentItem(
                            source_path=web_paths.AbsolutePath(
                                posixpath.join(source_vhosts_dir, site_vhost_name, "pd")
                            ),
                            target_path=web_paths.SiteProtectedDirs(subscription.converted_dump, site),
                            skip_if_source_not_exists=True,
                            fix_application_paths=False,
                        )
                    )

                    source_logs_subdir = posixpath.join(
                        source_vhosts_dir, site_vhost_name,
                        "statistics", "logs"
                    )
                    source_statistics_subdir = posixpath.join(
                        source_vhosts_dir, site_vhost_name,
                        "statistics"
                    )
                    source_statistics_exclude = ["/logs"]

                tocopy.extend([
                    # site logs
                    CopyWebContentItem(
                        source_path=web_paths.AbsolutePath(source_logs_subdir),
                        target_path=web_paths.SiteLogs(subscription.converted_dump, site),
                        skip_if_source_not_exists=True,
                        fix_application_paths=False,
                    ),
                    # site statistics
                    CopyWebContentItem(
                        source_path=web_paths.AbsolutePath(source_statistics_subdir),
                        target_path=web_paths.SiteStatistics(subscription.converted_dump, site),
                        exclude=source_statistics_exclude,
                        skip_if_source_not_exists=True,
                        fix_application_paths=False,
                    ),
                ])
            elif subscription.web_source_server.plesk_version >= (8, 0):  # plesk #8.x and #9.x
                pass

        return tocopy

    @staticmethod
    def _get_site_www_roots(subscription):
        """Get set containing all www roots of sites of all domains inside specified subscription

        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        :rtype: set[str | unicode]
        """
        site_www_roots = set()
        for domain in subscription.converted_dump.iter_domains():
            if domain.www_root is not None:
                site_www_roots.add(domain.www_root)

        return site_www_roots


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

        :type global_context: parallels.plesk.source.cpanel.global_context.CpanelGlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        :rtype: list[parallels.core.utils.paths.copy_web_content.CopyWebContentItem]
        """
        vhost_name = subscription.name_idn
        source_server = subscription.web_source_server
        """:type: parallels.plesk.source.plesk.server.PleskSourceServer"""
        www_roots = self._get_site_www_roots(subscription)
        security_files = [get_main_security_file()] + list_webuser_security_files(subscription)

        def compose_webspace_root_exclude(lst):
            return [
                '/%s' % name for name in lst
                if all(not path_startswith(normalize_path(name), www_root) for www_root in www_roots)
            ]

        tocopy = [
            # content
            CopyWebContentItem(
                source_path=web_paths.VirtualHostsPath(vhost_name + '/'),
                target_path=web_paths.WebspaceRoot(subscription.converted_dump),
                exclude=compose_webspace_root_exclude(
                    [u"statistics", u"subdomains"]
                ) + [security_file for security_file in security_files],
                skip_if_source_not_exists=False
            ),
            # subscription logs
            CopyWebContentItem(
                source_path=web_paths.VirtualHostsPath(u"%s/statistics/logs/" % vhost_name),
                target_path=web_paths.WebspaceLogs(subscription.converted_dump),
                exclude=[],
                skip_if_source_not_exists=True,
                fix_application_paths=False,
            ),
            CopyWebContentItem(
                source_path=web_paths.VirtualHostsPath(u"%s/logs/" % vhost_name),
                target_path=web_paths.WebspaceLogs(subscription.converted_dump),
                exclude=[],
                skip_if_source_not_exists=True,
                fix_application_paths=False,
            ),
            # subscription statistics
            CopyWebContentItem(
                source_path=web_paths.VirtualHostsPath(u"%s/statistics/" % vhost_name),
                target_path=web_paths.WebspaceMainDomainStatistics(subscription.converted_dump),
                exclude=[u"/logs"],
                skip_if_source_not_exists=True,
                fix_application_paths=False,
            ),
        ]

        for site in subscription.converted_dump.iter_sites():
            site_vhost_name = site.name.encode('idna')

            if source_server.plesk_version >= (12, 0):  # Plesk 12.x
                tocopy.extend([
                    # site statistics
                    CopyWebContentItem(
                        source_path=web_paths.VirtualHostsPath(
                            u"%s/.plesk/statistics/%s" % (vhost_name, site_vhost_name)
                        ),
                        target_path=web_paths.SiteStatistics(subscription.converted_dump, site),
                        exclude=[],
                        skip_if_source_not_exists=True,
                        fix_application_paths=False,
                    ),
                ])
            elif source_server.plesk_version >= (10, 0):  # Plesk 10 and 11
                source_logs_subdir = u"%s/statistics/logs" % site_vhost_name
                tocopy.extend([
                    # site logs
                    CopyWebContentItem(
                        source_path=web_paths.VirtualHostsPath(source_logs_subdir),
                        target_path=web_paths.WebspaceLogs(subscription.converted_dump),
                        exclude=[],
                        skip_if_source_not_exists=True,
                        fix_application_paths=False,
                    ),
                    # site statistics
                    CopyWebContentItem(
                        source_path=web_paths.VirtualHostsPath(u"%s/statistics" % site_vhost_name),
                        target_path=web_paths.SiteStatistics(subscription.converted_dump, site),
                        exclude=[u'/logs'],
                        skip_if_source_not_exists=True,
                        fix_application_paths=False,
                    ),
                ])
            else:
                # Plesk 8 and 9
                if site.hosting_type == 'vrt_hst':
                    # subdomains with physical hosting (living under subdomains/)
                    # have separate stats and logs, that need to be copied
                    source_site_subdir = "%s/subdomains/%s/" % (vhost_name, site.short_name.encode('idna'))
                    source_stats_subdir = u"%sstatistics/" % source_site_subdir
                    source_logs_subdir = u"%sstatistics/logs/" % source_site_subdir
                    tocopy.extend([
                        # subdomain logs
                        CopyWebContentItem(
                            source_path=web_paths.VirtualHostsPath(source_logs_subdir),
                            target_path=web_paths.WebspaceLogs(subscription.converted_dump),
                            exclude=[],
                            skip_if_source_not_exists=True,
                            fix_application_paths=False,
                        ),
                        # subdomain stats
                        CopyWebContentItem(
                            source_path=web_paths.VirtualHostsPath(source_stats_subdir),
                            target_path=web_paths.SiteStatistics(subscription.converted_dump, site),
                            exclude=[u'/logs'],
                            skip_if_source_not_exists=True,
                            fix_application_paths=False,
                        ),
                    ])
                    # copy all remaining stuff as content
                    tocopy.extend([
                        CopyWebContentItem(
                            source_path=web_paths.VirtualHostsPath(source_site_subdir),
                            target_path=web_paths.WebspacePathTemplate(
                                subscription.converted_dump,
                                '{webspace_root}/subdomains/%s' % site.short_name.encode('idna')
                            ),
                            exclude=[u'/statistics'],
                            skip_if_source_not_exists=False,
                        )
                    ])
                else:
                    # Subdomains with subdir hosting (living under httpdocs/)
                    # do not have separate stats, but have separate log
                    # Logs will be copied automatically with subscription's logs
                    pass

        return tocopy

    @staticmethod
    def _get_site_www_roots(subscription):
        """Get set containing all www roots of sites of all domains inside specified subscription

        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        :rtype: set[str | unicode]
        """
        site_www_roots = set()
        for domain in subscription.converted_dump.iter_domains():
            if domain.www_root is not None:
                site_www_roots.add(normalize_path(domain.www_root))

        return site_www_roots
