from parallels.core import messages
from parallels.core.actions.base.subscription_action import SubscriptionAction
from parallels.core.actions.post_migration_checks.utils import check_web_ip, should_run_post_migration_checks
from parallels.core.hosting_check.run_checks import run_entities
from parallels.core.logging import get_logger
from parallels.core.reports.model.issue import Issue
from parallels.hosting_check import DomainWebService

logger = get_logger(__name__)


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

        :rtype: str | unicode
        """
        return messages.ACTION_TEST_SITES_DESCRIPTION

    def get_failure_message(self, global_context, subscription):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        :rtype: str | unicode
        """
        return messages.ACTION_TEST_SITES_FAILURE

    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):
        if not should_run_post_migration_checks(global_context, 'sites'):
            return False

        if not subscription.converted_dump.is_enabled or not subscription.converted_dump.is_webspace_enabled:
            logger.debug(messages.SKIPPED_CHECKING_SITES_SUBSCRIPTION_S_BECAUSE % subscription.name)
            return False
        return True

    def run(self, global_context, subscription):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        """
        subscription_report = subscription.get_report(global_context.post_migration_check_report_writer)
        for domain in subscription.converted_dump.iter_domains():
            if subscription.is_fake and domain.name == subscription.name:
                continue

            web_site_report = subscription_report.subtarget(
                u"IIS web site" if subscription.web_target_server.is_windows() else u"Apache web site",
                domain.name
            )
            web_site_entities = self._get_web_site_check_entities(subscription, domain.name, web_site_report)
            run_entities(global_context, web_site_entities, web_site_report)

    @staticmethod
    def _get_web_site_check_entities(subscription, domain_name, report):
        """
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        :type domain_name: str | unicode
        :type report: parallels.core.reports.model.report.Report
        """
        result = []

        converted_domain = subscription.converted_dump.get_domain(domain_name)
        raw_domain = subscription.raw_dump.get_domain(domain_name)
        raw_subscription = subscription.raw_dump

        # if there is no site, do not check it
        if converted_domain.hosting_type == 'none':
            logger.debug(
                messages.SKIPPED_CHECKING_SITES_DOMAIN_S_BECAUSE % domain_name
            )
            return result

        if not converted_domain.is_enabled:
            logger.debug(
                messages.SKIPPED_CHECKING_SITE_S_SUBSCRIPTION_S % (
                    domain_name, subscription.name
                )
            )
            return result

        if converted_domain.is_maintenance:
            logger.debug(
                messages.SKIPPED_CHECKING_SITE_S_SUBSCRIPTION_S_1 % (
                    domain_name, subscription.name
                )
            )
            return result

        # retrieve src_ip
        # (any) H-Sphere site may have different web IP than
        # the corresponding H-Sphere subscription has So, first try to use
        # site's ip address, and if it's not defined, use subscription's IP
        # address.
        src_ip = (
            raw_domain.web_ips.v4 or raw_domain.web_ips.v6 or
            raw_subscription.ip or raw_subscription.ipv6
        )
        if src_ip is None:
            warnmsg = (
                messages.SETTINGS_DOMAIN_S_SOURCE_SERVER_ARE % domain_name
            )
            logger.error(warnmsg)
            report.add_issue(
                'real_check_web_failure', Issue.SEVERITY_WARNING, warnmsg,
                messages.RESOLVE_INCONSISTENCY_SOURCE_SERVER
            )
            return result

        if not check_web_ip(report, subscription, domain_name):
            return result

        # protocols
        protocols = ['http']
        if converted_domain.is_enable_ssl:
            protocols.append('https')

        def get_domain_aps_urls(protocol):
            urls = []
            for application in converted_domain.get_direct_aps_applications():
                application_domain_urls = \
                    application.get_public_urls()
                urls.extend([
                    domain_relative_url
                    for aps_protocol, domain_relative_url
                    in application_domain_urls
                    if aps_protocol == protocol
                ])
            return urls

        web_target_server = subscription.web_target_server

        def _get_error_logs():
            if web_target_server is not None \
                    and not web_target_server.is_windows():
                server = web_target_server.get_hosting_server()
                return server.get_unix_vhost_error_log_files(domain_name)
            else:
                return None

        dst_ips = [subscription.target_web_ip or subscription.target_web_ipv6]
        for dst_ip in dst_ips:
            for protocol in protocols:
                result.append(
                    DomainWebService(
                        domain_name=domain_name,
                        web_server_ip=dst_ip,
                        protocol=protocol,
                        source_web_server_ip=src_ip,
                        aps_domain_relative_urls=get_domain_aps_urls(protocol),
                        server=web_target_server,
                        error_logs=_get_error_logs(),
                        www_alias_enabled=converted_domain.www_alias_enabled
                    )
                )

        return result
