import json
from os import path

from django import forms
from django.core.exceptions import ValidationError

from .widgets import AddressWidget

basepath = path.dirname(__file__)
filepath = path.abspath(path.join(basepath, "static", "addressfield.min.json"))
with open(filepath, encoding="utf8") as address_data:
    countries = json.load(address_data)["options"]

VALIDATION_DATA = {country["iso"]: country for country in countries}

ADDRESS_FIELDS_ORDER = [
    "thoroughfare",
    "premise",
    "localityname",
    "administrativearea",
    "postalcode",
    "country",
]


def flatten_data(data):
    flattened = {}
    for d in data:
        for k, v in d.items():
            if isinstance(v, list):
                value = flatten_data(v)
            else:
                value = {k: v}
            flattened.update(value)
    return flattened


class AddressField(forms.CharField):
    """
    The field stores the address in a flattened form,
    so the locality components are on the same level as country or premise
    """

    widget = AddressWidget
    data = VALIDATION_DATA

    def clean(self, value, **kwargs):
        country = value["country"]
        try:
            country_data = self.data[country]
        except KeyError:
            raise ValidationError("Invalid country selected") from None

        fields = flatten_data(country_data["fields"])

        missing_fields = set(country_data["required"]) - {
            field for field, value in value.items() if value
        }
        if missing_fields:
            missing_field_name = [fields[field]["label"] for field in missing_fields]
            raise ValidationError(
                "Please provide data for: {}".format(", ".join(missing_field_name))
            )

        return super().clean(value, **kwargs)

    def to_python(self, value):
        return json.dumps(value)

    def prepare_value(self, value):
        try:
            # Handle empty value with "or".
            return json.loads(value or {})
        except TypeError:
            return value