# passerelle - uniform access to multiple data sources and services
#
# MIT License
# Copyright (c) 2020  departement-loire-atlantique
#
# GNU Affero General Public License
# Copyright (C) 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/>.
from django.db import models
from django.utils.translation import gettext_lazy as _

from passerelle.sms.models import SMSResource
from passerelle.utils.jsonresponse import APIError

BASE_API = 'https://contact-everyone.orange-business.com/api/v1.2/'
URL_TOKEN = BASE_API + 'oauth/token'
URL_GROUPS = BASE_API + 'groups'
URL_DIFFUSION = BASE_API + 'groups/%s/diffusion-requests'


class OrangeError(APIError):
    pass


def get_json(response):
    try:
        return response.json()
    except ValueError:
        raise OrangeError('Orange returned Invalid JSON content: %s' % response.text)


class OrangeSMSGateway(SMSResource):
    hide_description_fields = ['groupname']

    username = models.CharField(
        verbose_name=_('Identifier'),
        max_length=64,
        help_text=_(
            'Please remove any SMS sending restrictions in the Contact Everyone '
            'solution, especially on authorized sending periods.'
        ),
    )
    password = models.CharField(verbose_name=_('Password'), max_length=64)
    groupname = models.CharField(verbose_name=_('Group'), max_length=64)

    provide_sender = models.BooleanField(
        _('Use sender configurated with Publik'),
        default=False,
        help_text=_('Sender name must be allowed by orange'),
    )

    class Meta:
        verbose_name = _('Orange')
        db_table = 'sms_orange'

    def get_access_token(self):
        headers = {'content-type': 'application/x-www-form-urlencoded'}
        params = {'username': self.username, 'password': self.password}
        response = self.requests.post(URL_TOKEN, data=params, headers=headers)
        if response.status_code != 200:
            raise APIError('Bad username or password: %s, %s' % (response.status_code, response.text))
        response_json = get_json(response)
        if 'access_token' not in response_json:
            raise OrangeError('Orange do not return access token')
        return response_json['access_token']

    def group_id_from_name(self, access_token):
        headers = {'authorization': 'Bearer %s' % access_token}
        response = self.requests.get(URL_GROUPS, headers=headers)
        if response.status_code != 200:
            raise APIError('Bad token: %s, %s' % (response.status_code, response.text))
        response_json = get_json(response)
        group_id = None
        for group in response_json:
            if group['name'] == self.groupname:
                group_id = group['id']
                break
        if not group_id:
            raise APIError('Group name not found: ' + self.groupname)
        return group_id

    def diffusion(self, access_token, group_id, destinations, message, sender):
        headers = {
            'content-type': 'application/json',
            'authorization': 'Bearer %s' % access_token,
        }
        payload = {
            'name': 'Send a SMS from passerelle',
            'msisdns': destinations,
            'smsParam': {'encoding': 'GSM7', 'body': message},
        }
        if self.provide_sender:
            payload['smsParam']['senderName'] = sender
        response = self.requests.post(URL_DIFFUSION % group_id, json=payload, headers=headers)
        if response.status_code != 201:
            raise OrangeError('Orange fails to send SMS: %s, %s' % (response.status_code, response.text))
        return get_json(response)

    def send_msg(self, text, sender, destinations, **kwargs):
        '''Send a SMS using the Orange provider'''

        access_token = self.get_access_token()
        group_id = self.group_id_from_name(access_token)
        self.diffusion(access_token, group_id, destinations, text, sender)
        # credit consumed is unknown
