import urlparse
import unicodedata

from django.db import models
from django.utils.http import urlencode
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone

from passerelle.base.models import BaseResource
from passerelle.utils.api import endpoint


class BaseAdresse(BaseResource):
    service_url = models.CharField(
        max_length=128, blank=False,
        default='https://api-adresse.data.gouv.fr/',
        verbose_name=_('Service URL'),
        help_text=_('Base Adresse Web Service URL'))

    category = _('Geographic information system')

    zipcode = models.CharField(max_length=5, blank=True,
                                   verbose_name=_('Postal code to get streets'),
                                   help_text=_('Postal code to get the streets from.'))

    class Meta:
        verbose_name = _('Base Adresse Web Service')

    @classmethod
    def get_icon_class(cls):
        return 'gis'

    @endpoint(pattern='(?P<q>.+)?$')
    def search(self, request, q, zipcode='', **kwargs):
        if kwargs.get('format', 'json') != 'json':
            raise NotImplementedError()

        scheme, netloc, path, params, query, fragment = urlparse.urlparse(self.service_url)
        path = '/search/'
        query = urlencode({
            'q': q, 'limit': 1,
            'postcode': zipcode,
        })

        url = urlparse.urlunparse((scheme, netloc, path, params, query, fragment))

        result_response = self.requests.get(url)
        result = []

        for feature in result_response.json().get('features'):
            if not feature['geometry']['type'] == 'Point':
                continue  # skip unknown
            result.append({
                'lon': str(feature['geometry']['coordinates'][0]),
                'lat': str(feature['geometry']['coordinates'][1]),
                'display_name': feature['properties']['label'],
            })
            break

        return result

    @endpoint()
    def reverse(self, request, lat, lon, **kwargs):
        if kwargs.get('format', 'json') != 'json':
            raise NotImplementedError()

        scheme, netloc, path, params, query, fragment = urlparse.urlparse(self.service_url)
        path = '/reverse/'
        query = urlencode({'lat': lat, 'lon': lon})
        url = urlparse.urlunparse((scheme, netloc, path, params, query, fragment))

        result_response = self.requests.get(url)
        result = None

        for feature in result_response.json().get('features'):
            if not feature['geometry']['type'] == 'Point':
                continue  # skip unknown
            result = {}
            result['lon'] = str(feature['geometry']['coordinates'][0])
            result['lat'] = str(feature['geometry']['coordinates'][1])
            result['address'] = {'country': 'France'}
            for prop in feature['properties']:
                if prop in ('city', 'postcode'):
                    result['address'][prop] = feature['properties'][prop]
                elif prop == 'housenumber':
                    result['address']['house_number'] = feature['properties'][prop]
                elif prop == 'label':
                    result['display_name'] = feature['properties'][prop]
                elif prop == 'name':
                    house_number = feature['properties'].get('housenumber')
                    value = feature['properties'][prop]
                    if house_number and value.startswith(house_number):
                        value = value[len(house_number):].strip()
                    result['address']['road'] = value
        return result

    @endpoint(serializer_type='json-api')
    def streets(self, request, zipcode=None, q=None, page_limit=None):
        result = []
        streets = StreetModel.objects.all()
        if q:
            unaccented_q = unicodedata.normalize('NFKD', q).encode('ascii', 'ignore').lower()
            streets = streets.filter(unaccent_name__icontains=unaccented_q)

        if zipcode:
            streets = streets.filter(zipcode__startswith=zipcode)

        if page_limit:
            streets = streets[:page_limit]

        for street in streets:
            result.append({'id': street.id,
                           'text': street.name,
                           'type': street.type,
                           'city': street.city,
                           'citycode': street.citycode,
                           'zipcode': street.zipcode})

        return result


class StreetModel(models.Model):

    city = models.CharField(_('City'), max_length=100)
    name = models.CharField(_('Street name'), max_length=150)
    unaccent_name = models.CharField(_('Street name ascii char'), max_length=150, null=True)
    zipcode = models.CharField(_('Postal code'), max_length=5)
    type = models.CharField(_('Street type'), max_length=30)
    citycode = models.CharField(_('City Code'), max_length=5)
    last_update = models.DateTimeField(_('Last update'), null=True, auto_now=True)

    class Meta:
        ordering = ['unaccent_name', 'name']

    def __unicode__(self):
        return unicode(self.name)

    def save(self, *args, **kwargs):
        self.unaccent_name = unicodedata.normalize('NFKD', self.name).encode('ascii', 'ignore')
        super(StreetModel, self).save(*args, **kwargs)
