import json
import unicodedata

from django.http import Http404
from django.views.generic.base import View
from django.views.generic.detail import SingleObjectMixin, DetailView

from passerelle import utils

from .models import Gdc, phpserialize, phpserialize_loads, SOAPpy



class StatusView(View, SingleObjectMixin):
    model = Gdc

    def get(self, request, *args, **kwargs):
        if SOAPpy is None:
            raise Http404
        ref = int(kwargs.get('ref'))
        server = SOAPpy.SOAPProxy(self.get_object().service_url)
        soap_result = phpserialize_loads(server.getDemandeControleurEtat(ref)['listeInfo'])
        result = {
            'status_id': soap_result['STATUT_ID']
        }
        return utils.response_for_json(request, {'data': result})


def get_voies(service_url, insee):
    server = SOAPpy.SOAPProxy(service_url)
    soap_result = phpserialize_loads(server.getListeVoieCommune(insee)['listeVoie'])
    result = []
    prefix_map = {
            'ALL': 'ALLEE',
            'AUTO': 'AUTOROUTE',
            'AV': 'AVENUE',
            'BASS': 'BASSIN',
            'BD': 'BOULEVARD',
            'CAR': 'CARREFOUR',
            'CHE': 'CHEMIN',
            'COUR': 'COUR',
            'CRS': 'COURS',
            'DESC': 'DESCENTE',
            'DOM': 'DOMAINE',
            'ENCL': 'ENCLOS',
            'ESP': 'ESPLANADE',
            'ESPA': 'ESPACE',
            'GR': '', # "GR GRAND-RUE JEAN MOULIN"
            'IMP': 'IMPASSE',
            'JARD': 'JARDIN',
            'MAIL': '', # "MAIL LE GRAND MAIL"
            'PARC': 'PARC',
            'PARV': '', # "PARV PARVIS DE LA LEGION D HONNEUR"
            'PAS': 'PASSAGE',
            'PL': 'PLACE',
            'PLAN': 'PLAN',
            'PONT': 'PONT',
            'QUA': 'QUAI',
            'R': 'RUE',
            'RAMB': '', # "RAMB RAMBLA DES CALISSONS"
            'RPT': 'ROND-POINT',
            'RTE': 'ROUTE',
            'SQ': 'SQUARE',
            'TSSE': '', # "TSSE TERRASSE DES ALLEES DU BOIS"
            'TUN': 'TUNNEL',
            'VIAD': 'VIADUC',
            'VOI': 'VOIE',
    }
    for k, v in soap_result.items():
        for prefix, full in prefix_map.items():
            if v.startswith(prefix + ' '):
                v = (full + v[len(prefix):]).strip()
        result.append({'id': k, 'text': v})
    result.sort(lambda x,y: cmp(x['id'], y['id']))
    return result


class VoiesView(View, SingleObjectMixin):
    model = Gdc

    def get(self, request, *args, **kwargs):
        if SOAPpy is None:
            raise Http404
        insee = kwargs.get('insee')
        result = get_voies(self.get_object().service_url, insee)
        q = request.GET.get('q')
        if q:
            q = q.lower()
            result = [x for x in result if q in x['text'].lower()]
        return utils.response_for_json(request, {'data': result})


class PostDemandeView(View, SingleObjectMixin):
    model = Gdc

    @utils.protected_api('can_post_request')
    def post(self, request, *args, **kwargs):
        # <wsdl:message name='addDemandeExterneParticulierRequest'>
        #   <wsdl:part name='nom' type='xsd:string'></wsdl:part>
        #   <wsdl:part name='prenom' type='xsd:string'></wsdl:part>
        #   <wsdl:part name='telephone' type='xsd:string'></wsdl:part>
        #   <wsdl:part name='mail' type='xsd:string'></wsdl:part>
        #   <wsdl:part name='objet_externe' type='xsd:int'></wsdl:part>
        #   <wsdl:part name='commentaire' type='xsd:string'></wsdl:part>
        #   <wsdl:part name='insee_commune' type='xsd:int'></wsdl:part>
        #   <wsdl:part name='voie_id' type='xsd:string'></wsdl:part>
        #   <wsdl:part name='voie_num' type='xsd:string'></wsdl:part>
        # </wsdl:message>
        if SOAPpy is None:
            raise Http404
        data = json.loads(request.body)
        server = SOAPpy.SOAPProxy(self.get_object().service_url)
        voie_id = data['fields'].get('voie_raw')
        voie_str = data['fields'].get('voie')
        insee = data['fields'].get('commune_raw')
        if voie_str and not voie_id:
            # look for a voie with that name, so we can provide an identifier
            # to gdc
            voies = get_voies(self.get_object().service_url, insee)
            normalized_voie = unicodedata.normalize('NFKD', voie_str).encode('ascii', 'ignore').decode('ascii')
            normalized_voie = normalized_voie.upper()
            for k, v in voies:
                if v == normalized_voie or k == normalized_voie:
                    voie_id = k
                    break

        objet = self.request.GET.get('objet')
        if objet is None:
            objet = data['fields'].get('objet_raw')

        kwargs = {
            'nom': data['fields'].get('nom'),
            'prenom': data['fields'].get('prenom'),
            'mail': data['fields'].get('mail'),
            'telephone': data['fields'].get('telephone'),
            'objet_externe': objet,
            'commentaire': data['fields'].get('commentaire'),
            'insee_commune': insee,
            'voie_id': voie_id,
            'voie_str': voie_str,
            'voie_num': data['fields'].get('voie_num'),
        }

        if 'picture' in data['fields'] and data['fields']['picture']:
            kwargs['picture_filename'] = data['fields']['picture']['filename']
            kwargs['picture_b64'] = data['fields']['picture']['content']

        soap_result = server.addDemandeExterneParticulier(**kwargs)
        result = phpserialize_loads(soap_result['listeInfo'])
        result = {'result': soap_result['code_retour'],
                'display_id': result.get('IDENTIFIANT'),
                'id': result.get('IDENTIFIANT'),
                'details': result}
        return utils.response_for_json(request, result)


class GdcDetailView(DetailView):
    model = Gdc
    template_name = 'gdc/gdc_detail.html'

    def get_context_data(self, **kwargs):
        context = super(GdcDetailView, self).get_context_data(**kwargs)
        if phpserialize is None:
            context['missing_phpserialize'] = True
        if SOAPpy is None:
            context['missing_soappy'] = True
        return context
