# Passerelle - uniform access to data and services
# Copyright (C) 2015-2020  Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


import json

from django.utils.encoding import force_str
from django.views.generic.base import View
from django.views.generic.detail import DetailView, SingleObjectMixin

from passerelle import utils
from passerelle.utils.conversion import normalize

from .models import Gdc, phpserialize, phpserialize_loads


class GdcCrash(Exception):
    pass


class StatusView(View, SingleObjectMixin):
    model = Gdc

    def get(self, request, *args, **kwargs):
        ref = int(kwargs.get('ref'))
        service = self.get_object()
        try:
            resp = service.call_soap('getDemandeControleurEtat', ref)
            soap_result = resp.findall('.//listeInfo')[0].text
        except Exception:
            # if there's a gdc crash don't return anything and hopefully the
            # w.c.s. workflow will handle that and retry later.
            result = {'result': 'gdc soap crash'}
        else:
            gdc_result = phpserialize_loads(soap_result)
            result = {
                'status_id': gdc_result['STATUT_ID'],
            }
        return utils.response_for_json(request, {'data': result})


def get_voies(service, insee):
    resp = service.call_soap('getListeVoieCommune', insee)
    soap_result = phpserialize_loads(resp.findall('.//listeVoie')[0].text)
    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(key=lambda x: x['id'])
    return result


class VoiesView(View, SingleObjectMixin):
    model = Gdc

    def get(self, request, *args, **kwargs):
        insee = kwargs.get('insee')
        try:
            result = get_voies(self.get_object(), insee)
        except GdcCrash:
            result = []
        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>
        data = json.loads(request.body)
        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
            try:
                voies = get_voies(self.get_object(), insee)
            except GdcCrash:
                result = {'result': 'gdc soap crash'}
                return utils.response_for_json(request, result)
            normalized_voie = normalize(voie_str).upper()
            for k, v in voies:
                if normalized_voie in (v, k):
                    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': int(objet),
            'commentaire': data['fields'].get('commentaire'),
            'insee_commune': int(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']

        try:
            resp = self.get_object().call_soap('addDemandeExterneParticulier', **kwargs)
        except OSError:
            result = {'result': 'gdc soap crash'}
        else:
            code_retour = force_str(resp.findall('.//code_retour')[0].text)
            result = phpserialize_loads(resp.findall('.//listeInfo')[0].text)
            result = {
                '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().get_context_data(**kwargs)
        if phpserialize is None:
            context['missing_phpserialize'] = True
        return context
