from agenda_culturel.models import ReferenceLocation
import re
import unicodedata


class PlaceGuesser:

    def __init__(self):
        self.__citynames = list(ReferenceLocation.objects.values_list("name__lower__unaccent", "name")) + [("clermont-fd", "Clermont-Ferrand"), ("aurillac", "Aurillac"), ("montlucon", "Montluçon"), ("montferrand", "Clermont-Ferrand")]
        self.__citynames = [(x[0].replace("-", " "), x[1]) for x in self.__citynames]

    def __remove_accents(self, input_str):
        if input_str is None:
            return None
        nfkd_form = unicodedata.normalize("NFKD", input_str)
        return "".join([c for c in nfkd_form if not unicodedata.combining(c)])


    def __guess_is_address(self, part):
        toponyms = ["bd", "rue", "avenue", "place", "boulevard", "allee", ]
        part = part.strip()
        if re.match(r'^[0-9]', part):
            return True
        
        elems = part.split(" ")
        return any([self.__remove_accents(e.lower()) in toponyms for e in elems])
        

    def __clean_address(self, addr):
        toponyms = ["bd", "rue", "avenue", "place", "boulevard", "allée", "bis", "ter", "ZI"]
        for t in toponyms:
            addr = re.sub(" " + t + " ", " " + t + " ", addr, flags=re.IGNORECASE)
        return addr

    def __guess_city_name(self, part):
        part = part.replace(" - ", "-").replace("(", "").replace(")", "").strip()
        if len(part) == 0:
            return None
        part = self.__remove_accents(part.lower()).replace("-", " ")
        match = [x[1] for x in self.__citynames if x[0] == part]
        if len(match) > 0:
            return match[0]
        else:
            return None

    def __guess_city_name_postcode(self, part):
        with_pc = re.search(r'^(.*)(([0-9][ ]*){5})(.*)$', part)
        if with_pc:
            p1 = self.__guess_city_name(with_pc.group(1).strip())
            postcode = with_pc.group(2).replace(" ", "")
            p2 = self.__guess_city_name(with_pc.group(4).strip())
            return postcode, p2, p1
        else:
            return None, self.__guess_city_name(part), None

    def __guess_name_address(self, part):
        with_num = re.search(r'^(([^0-9])+)([0-9]+)(.*)', part)
        if with_num:
            name = with_num.group(1)
            return name, part[len(name):]
        else:
            return "", part

    def guess_address_elements(self, alias):
        parts = re.split(r'[,/à]', alias)
        parts = [p1 for p1 in [p.strip() for p in parts] if p1 != "" and p1.lower() != "france"]

        name = ""
        address = ""
        postcode = ""
        city = ""
        possible_city = ""

        oparts = []
        for part in parts:
            p, c, possible_c = self.__guess_city_name_postcode(part)
            if not possible_c is None:
                possible_city = possible_c 
            if not c is None and city == "":
                city = c
            if not p is None and postcode == "":
                postcode = p
            if p is None and c is None:
                oparts.append(part)

        if city == "" and possible_city != "":
            city = possible_city
        else:
            if len(oparts) == 0 and not possible_city != "":
                oparts = [possible_city]

        if city == "":
            alias_simple = self.__remove_accents(alias.lower()).replace("-", " ")
            mc = [x[1] for x in self.__citynames if alias_simple.endswith(" " + x[0])]
            if len(mc) == 1:
                city = mc[0]




        if len(oparts) > 0:
            if not self.__guess_is_address(oparts[0]):
                name = oparts[0]
                address = ", ".join(oparts[1:])
            else:
                name, address = self.__guess_name_address(", ".join(oparts))

        address = self.__clean_address(address)

        if name == "" and possible_city != "" and possible_city != city:
            name = possible_city

        return name, address, postcode, city

