# passerelle - uniform access to multiple data sources and services
# Copyright (C) 2018 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 urllib import parse as urlparse

from django.db import models
from django.utils import timezone
from django.utils.dateparse import parse_date, parse_time
from django.utils.translation import gettext_lazy as _
from requests import RequestException

from passerelle.base.models import BaseResource
from passerelle.utils.api import endpoint
from passerelle.utils.http_authenticators import HawkAuth
from passerelle.utils.jsonresponse import APIError


class ArpegeECP(BaseResource):
    log_requests_errors = False

    category = _('Business Process Connectors')
    webservice_base_url = models.URLField(_('Webservice Base URL'))
    hawk_auth_id = models.CharField(_('Hawk Authentication id'), max_length=64)
    hawk_auth_key = models.CharField(_('Hawk Authentication secret'), max_length=64)

    class Meta:
        verbose_name = _('Arpege ECP')

    def check_status(self):
        url = urlparse.urljoin(self.webservice_base_url, 'Hello')
        try:
            response = self.requests.get(url, auth=HawkAuth(self.hawk_auth_id, self.hawk_auth_key))
            response.raise_for_status()
        except RequestException as e:
            raise Exception('Arpege server is down: %s' % e)
        if not response.json().get('Data'):
            raise Exception('Invalid credentials')
        return {'data': response.json()['Data']}

    def get_access_token(self, NameID):
        url = urlparse.urljoin(self.webservice_base_url, 'LoginParSubOIDC')
        try:
            response = self.requests.post(
                url, auth=HawkAuth(self.hawk_auth_id, self.hawk_auth_key), json={'subOIDC': NameID}
            )
            response.raise_for_status()
        except RequestException as e:
            raise APIError('Arpege server is down: %s' % e)
        try:
            result = response.json()
        except ValueError:
            raise APIError('Arpege server is down: no JSON content returned, %r' % response.content[:1000])
        if result.get('Data'):
            if 'AccessToken' not in result['Data']:
                raise APIError('Error on LoginParSubOIDC: missing Data/AccessToken')
            if not isinstance(result['Data']['AccessToken'], str):
                raise APIError('Error on LoginParSubOIDC: Data/AccessToken is not string')
            return result['Data']['AccessToken']
        raise APIError('%s (%s)' % (result.get('LibErreur'), result.get('CodErreur')))

    @endpoint(
        name='api',
        pattern=r'^users/(?P<nameid>\w+)/forms$',
        perm='can_access',
        description='Returns user forms',
    )
    def get_user_forms(self, request, nameid):
        access_token = self.get_access_token(nameid)
        url = urlparse.urljoin(self.webservice_base_url, 'DemandesUsager')
        params = {'scope': 'data_administratives'}
        auth = HawkAuth(self.hawk_auth_id, self.hawk_auth_key, ext=access_token)
        try:
            response = self.requests.get(url, params=params, auth=auth)
            response.raise_for_status()
        except RequestException as e:
            raise APIError('Arpege server is down: %s' % e)
        data = []
        try:
            result = response.json()
        except ValueError:
            raise APIError('No JSON content returned: %r' % response.content[:1000])
        if not result.get('Data'):
            raise APIError("%s (%s)" % (result.get('LibErreur'), result.get('CodErreur')))
        for demand in result['Data']['results']:
            try:
                data_administratives = demand['data_administratives']
                receipt_time = parse_time(data_administratives['heure_depot'])
                receipt_date = parse_date(data_administratives['date_depot'])
            except (KeyError, TypeError) as e:
                raise APIError('Arpege error: %s %r' % (e, json.dumps(demand)[:1000]))
            d = {
                'url': demand['url'],
                'title': data_administratives.get('LibelleQualificationTypeDemande'),
                'name': data_administratives.get('LibelleQualificationTypeDemande'),
                'status': data_administratives.get('libelle_etat'),
                'form_receipt_time': receipt_time,
                'readable': True,
                'form_receipt_datetime': timezone.datetime.combine(receipt_date, receipt_time),
                'form_status_is_endpoint': data_administratives.get('date_fin_instruction') is not None,
            }
            data.append(d)
        return {'data': data}
