import json
import urllib2
from xml.etree import ElementTree

import dns.message, dns.query, dns.rdtypes.ANY.MX
import os

from plesk_mail_migrator.utils.list_utils import unique_list
from plesk_mail_migrator.utils.string_utils import is_empty

GOOGLE_DNS = '8.8.8.8'


def get_parent_domain_chain(domain_name):
    """Get chain of parent domains including domain itself.

    For example, for "a.b.example.com" this function should return
    ["a.b.example.com", "b.example.com", "example.com", "com"]

    :type domain_name: str | unicode
    :rtype: list[str | unicode]
    """
    result = []

    names = domain_name.split('.')
    for i in xrange(len(names)):
        result.append(".".join(names[i:]))

    return result


def get_first_mx_record(domain_name, dns_server=GOOGLE_DNS):
    """Get value of the first (by preference value) MX record for specified domain.

    When there are no MX records, the function returns None.

    By default the function asks Google DNS server, but you could override that by setting "dns_server" parameter.

    :type domain_name: str | unicode
    :type dns_server: str | unicode
    :rtype: str | unicode | None
    """
    dns_request = dns.message.make_query(domain_name, dns.rdatatype.MX, dns.rdataclass.IN)
    dns_response = dns.query.udp(dns_request, dns_server)
    result = [
        {
            'preference': rdata.preference,
            'exchange': rdata.exchange.to_text(True)
        }
        for rdset in dns_response.answer
        for rdata in rdset
    ]
    if len(result) > 0:
        result.sort(key=lambda r: r['preference'], reverse=True)
        return result[0]['exchange']
    else:
        return None


def load_mozilla_database():
    """Load autoconfig database of Mozilla/Thunderbird from local file and return it in simple format.

    Database in returned in simple format - dictionary:
    - keys - domain names of e-mail addresses
    - values - lists of hostnames of IMAP servers for corresponding e-mail domain
    For example: {
        ...
        'gmail.com': [
            'imap.gmail.com'
        ]
        ...
    }

    :rtype: dict[str | unicode, list[str | unicode]]
    """
    current_python_file_path = __file__
    while os.path.islink(current_python_file_path):
        current_python_file_path = os.readlink(current_python_file_path)

    current_python_dir_path = os.path.dirname(current_python_file_path)
    database_path = os.path.join(current_python_dir_path, 'autoconfig-db.json')

    with open(database_path) as fp:
        return json.load(fp)


def get_imap_servers_from_autodetect_url(url, domain_name, ca_bundle):
    """Load autodetect XML from specified URL, parse and return list of IMAP hosts for specified domain

    :type url: str | unicode
    :type domain_name: str | unicode
    :param str | unicode ca_bundle: Path to CA certificates bundle
    :rtype: list[str | unicode]
    """
    http_handler = urllib2.urlopen(url, cafile=ca_bundle)
    http_data = http_handler.read()
    tree = ElementTree.fromstring(http_data)

    result = []

    for server in tree.findall('emailProvider/incomingServer'):
        if server.attrib.get('type') != 'imap':
            continue

        hostname = server.findtext('hostname')
        if is_empty(hostname):
            continue

        imap_host = hostname.replace('%EMAILDOMAIN%', domain_name)

        if '%' in imap_host:
            # Skip all hostname templates which contain other variables than "%EMAILDOMAIN%",
            # not implemented (and seems useless)
            continue

        result.append(imap_host)

    return unique_list(result)
