from parallels.core.logging import get_logger
from parallels.core.utils.common import safe_string_repr
from parallels.hosting_check.utils.dns_utils import \
    DnsRequestTimeoutException, get_difference_between_dns_servers 
from parallels.hosting_check import \
    DomainIssue, Severity, DNSForwardingIssueType
from parallels.hosting_check.messages import MSG

logger = get_logger(__name__)


class DNSForwardingChecker(object):
    def __init__(
        self, max_difference_lines=3, 
        save_external_report_data_function=None
    ):
        self.max_difference_lines = max_difference_lines
        self.save_external_report_data_function = \
            save_external_report_data_function

    def check(self, domains_to_check):
        issues = []

        for domain_to_check in domains_to_check:

            for source_dns_server_ip in domain_to_check.source_dns_servers:
                self._check_signle_source_dns_server(
                    domain_to_check, source_dns_server_ip, 
                    issues
                )

        return issues

    def _check_signle_source_dns_server(
        self, domain_to_check, source_dns_server_ip, issues
    ):
        def add_issue(severity, category, problem):
            issues.append(
                DomainIssue(
                    domain_name=domain_to_check.domain_name, 
                    severity=severity, 
                    category=category, 
                    problem=problem
                )
            )

        logger.debug(MSG(
            'dns_forwarding_log_checking',
            source_dns_server_ip=source_dns_server_ip,
            domain=domain_to_check.domain_name
        ))

        try:
            difference = get_difference_between_dns_servers(
                domain_to_check.dns_records, 
                domain_to_check.target_dns_server, source_dns_server_ip
            )

            if len(difference) > 0:
                self._report_difference(
                    domain_to_check, source_dns_server_ip, difference, issues
                )
        except DnsRequestTimeoutException as e:
            logger.debug(u"Exception:", exc_info=e)
            # do not show any report comparing records - just a timeout
            # message
            add_issue(
                severity=Severity.WARNING,
                category=DNSForwardingIssueType.DNS_SERVER_TIMEOUT,
                problem=MSG(
                    DNSForwardingIssueType.DNS_SERVER_TIMEOUT,
                    source_dns_server_ip=e.server_ip
                )
            )

        except Exception as e:
            logger.debug(u"Exception:", exc_info=e)
            # do not show any report comparing records - just a general
            # failure message
            add_issue(
                severity=Severity.WARNING,
                category=DNSForwardingIssueType.INTERNAL_ERROR,
                problem=MSG(
                    DNSForwardingIssueType.INTERNAL_ERROR,
                    reason=safe_string_repr(e),
                    source_dns_server_ip=source_dns_server_ip
                )
            )

    def _report_difference(
        self, domain_to_check, source_dns_server_ip, difference, issues
    ):
        if (
            len(difference) <= self.max_difference_lines or
            self.save_external_report_data_function is None
        ):
            # put all differences to screen immediately
            difference_str = MSG(
                'dns_forwarding_difference_full',
                difference=u"\n".join(difference)
            )
        else: 
            # put first 3 differences to screen as an example, put all
            # other differences into a separate file
            filename = self.save_external_report_data_function(
                "dns.forwarding.difference.%s" % domain_to_check.domain_name,
                MSG(
                    'dns_forwarding_difference_file',
                    source_dns_server_ip=source_dns_server_ip,
                    target_dns_server_ip=domain_to_check.target_dns_server,
                    difference=u"\n".join(difference)
                )
            )
            difference_str = MSG(
                'dns_forwarding_difference_example',
                difference=u"\n".join(difference[:3]), 
                filename=filename
            )

        issues.append(
            DomainIssue(
                domain_name=domain_to_check.domain_name, 
                severity=Severity.WARNING,
                category=DNSForwardingIssueType.DIFFERENT_RECORDS,
                problem=MSG(
                    DNSForwardingIssueType.DIFFERENT_RECORDS,
                    source_dns_server_ip=source_dns_server_ip, 
                    target_dns_server_ip=domain_to_check.target_dns_server, 
                    difference=difference_str
                )
            )
        )
