# -*- coding: utf-8 -*-

import pytest
import mock
import requests

from django.core.wsgi import get_wsgi_application
from django.core.urlresolvers import reverse
from django.contrib.contenttypes.models import ContentType
from django.utils.http import urlencode

from passerelle.base.models import ApiUser, AccessRight
from passerelle.contrib.meyzieu_newsletters.models import MeyzieuNewsletters
from passerelle.contrib.meyzieu_newsletters.models import SubscriptionsGetError
from passerelle.contrib.meyzieu_newsletters.models import SubscriptionsSetError

pytestmark = pytest.mark.django_db

WS_URL = 'http://recette.meyzieu.fr/services/'
WS_API_KEY = '12345'
API_KEY = 'local'
TEST_USER = 'foo@example.com'

WS_NEWSLETERS_RETURN = {'fil_actu': [{'titre': u'Démocratie locale', 'id_rubrique': '20'},
                        {'titre': u'Aménagement urbain', 'id_rubrique': '53'}],
            'newsletter': [{'titre': u'Sortir', 'id_rubrique': '2'},
                        {'titre': u'Familles', 'id_rubrique': '3'}],
            u'push_mail': [{'titre': u'Le conseil municipal', 'id_rubrique': '9'},
                        {'titre': u'Rencontres de quartiers', 'id_rubrique': '21'},
                        {'titre': u"Offres d'emploi", 'id_rubrique': '30'},
                        {'titre': u'Marchés publics', 'id_rubrique': '31'},
                        {'titre': u'Environnement', 'id_rubrique': '46'},
                        {'titre': u'Restauration scolaire', 'id_rubrique': '76'},
                        {'titre': u'Publications', 'id_rubrique': '102'},
                        {'titre': u'Echo des cartables', 'id_rubrique': '104'},
                        {'titre': u'Travaux', 'id_rubrique': '134'}],
            'cap_meyzieu': [{'titre': u'Environnement', 'id_rubrique': '46'},
                        {'titre': 'Prévention - Santé', 'id_rubrique': '68'},
                        {'titre': u'Enfance Jeunesse', 'id_rubrique': '69'},
                        {'titre': u'Manifestations et activités', 'id_rubrique': '96'}],
            'autres_publications': [{'titre': u'Environnement', 'id_rubrique': '46'},
                        {'titre': u'Prévention - Santé', 'id_rubrique': '68'},
                        {'titre': u'Enfance Jeunesse', 'id_rubrique': '69'},
                        {'titre': u'Manifestations et activités', 'id_rubrique': '96'}
]}

WS_SUBSCRIPTIONS_RETURN = {'abonnement':
        {'newsletter': [{'id_abonnement': '2', 'auteur': TEST_USER}],
        'push_mail': [{'id_abonnement': '30', 'auteur': TEST_USER},
                      {'id_abonnement': '46', 'auteur': TEST_USER},
                      {'id_abonnement': '76', 'auteur': TEST_USER}]}
}

POST_SUBSCRIPTIONS = [{"id": "69", "text": "Enfance Jeunesse", "transports": []},
                      {"id": 76, "text": "Restauration scolaire", "transports": ["push_mail"]},
                      {"id": "46", "text": "Environnement", "transports": ["push_mail"]}
]

def mocked_requests_get(*args, **kwargs):
    method = kwargs['params'].get('method')
    class MockResponse:
        def __init__(self, json_data):
            self.json_data = json_data
        def json(self):
            return self.json_data

    if method == 'meyzieu.connection.getListRubrique':
        return MockResponse(WS_NEWSLETERS_RETURN)
    elif method == 'meyzieu.connection.getListAbonnement':
        return MockResponse(WS_SUBSCRIPTIONS_RETURN)
    else:
        return MockResponse({})

def set_subscriptions_connection_error(*args, **kwargs):
    if kwargs['params'].get('method') == 'meyzieu.connection.addAbonnement':
        raise requests.ConnectionError
    else:
        return mocked_requests_get(*args, **kwargs)

def get_subscriptions_connection_error(*args, **kwargs):
    raise requests.ConnectionError

@pytest.fixture
def setup():
    from webtest import TestApp
    api = ApiUser.objects.create(username='local', keytype='API', key=API_KEY)
    app = TestApp(get_wsgi_application())
    conn = MeyzieuNewsletters.objects.create(title='test', slug='push_mail',
                                             url=WS_URL, apikey=WS_API_KEY)
    obj_type = ContentType.objects.get_for_model(MeyzieuNewsletters)
    AccessRight.objects.create(codename='can_access',
                    apiuser=api, resource_type=obj_type,
                    resource_pk=conn.pk)
    return app, conn

@mock.patch('passerelle.contrib.meyzieu_newsletters.models.requests.get',
            side_effect=mocked_requests_get)
def test_get_newsletters(mock_get, setup):
    app, conn = setup
    resp = app.get(reverse('meyzieu-newsletters-types', kwargs={'slug': conn.slug}),
                   params={'apikey': API_KEY}, status=200)
    newsletters_ids = []
    newsletters_texts = []
    for v in WS_NEWSLETERS_RETURN.itervalues():
        for n in v:
            newsletters_ids.append(n['id_rubrique'])
            newsletters_texts.append(n['titre'])
    for newsletter in resp.json['data']:
        assert 'id' in newsletter
        assert newsletter['id'] in newsletters_ids
        assert 'text' in newsletter
        assert newsletter['text'] in newsletters_texts
        assert 'transports' in newsletter
        transports = newsletter['transports']
        for t in transports:
            assert 'id' in t
            assert 'text' in t

@mock.patch('passerelle.contrib.meyzieu_newsletters.models.requests.get',
            side_effect=mocked_requests_get)
def test_get_subscriptions_to_non_existing_newsletters(mock_get, setup):
    app, conn = setup
    resp = app.get(reverse('meyzieu-newsletters-subscriptions', kwargs={'slug': conn.slug}),
                   params={'apikey': API_KEY, 'email': TEST_USER}, status=200)
    subscriptions = WS_SUBSCRIPTIONS_RETURN['abonnement']
    subscriptions['push_mail'].append({'id_abonnement': '42', 'auteur': TEST_USER})
    subs = []
    for sub in subscriptions.itervalues():
        subs.extend([i['id_abonnement'] for i in sub])
    for subscription in resp.json['data']:
        assert 'text' in subscription
        assert 'transports' in subscription
        assert 'id' in subscription
        assert subscription['id'] in subs
        for transport in subscription['transports']:
            assert 'id' in transport
            assert transport['id'] in subscriptions

@mock.patch('passerelle.contrib.meyzieu_newsletters.models.requests.get',
            side_effect=mocked_requests_get)
def test_get_subscriptions(mock_get, setup):
    app, conn = setup
    resp = app.get(reverse('meyzieu-newsletters-subscriptions', kwargs={'slug': conn.slug}),
                   params={'apikey': API_KEY, 'email': TEST_USER}, status=200)
    subscriptions = WS_SUBSCRIPTIONS_RETURN['abonnement']
    subs = []
    for sub in subscriptions.itervalues():
        subs.extend([i['id_abonnement'] for i in sub])
    for subscription in resp.json['data']:
        assert 'text' in subscription
        assert 'transports' in subscription
        assert 'id' in subscription
        assert subscription['id'] in subs
        for transport in subscription['transports']:
            assert 'id' in transport
            assert transport['id'] in subscriptions

@mock.patch('passerelle.contrib.meyzieu_newsletters.models.requests.get',
            side_effect=get_subscriptions_connection_error)
def test_get_subscriptions_with_connection_error(mock_get, setup):
    app, conn = setup
    resp = app.get(reverse('meyzieu-newsletters-subscriptions', kwargs={'slug': conn.slug}),
                   params={'apikey': API_KEY, 'email': TEST_USER}, status=503)
    assert resp.json['err']
    assert resp.json['err_class'] == '%s.%s' % (SubscriptionsGetError.__module__,
                                                SubscriptionsGetError.__name__)
    assert resp.json['err_desc'] == 'error on getting subscriptions'

@mock.patch('passerelle.contrib.meyzieu_newsletters.models.requests.get',
            side_effect=mocked_requests_get)
def test_set_subscriptions(mock_get, setup):
    app, conn = setup
    url = reverse('meyzieu-newsletters-subscriptions', kwargs={'slug': conn.slug})
    url += '?' + urlencode({'apikey': API_KEY, 'email': TEST_USER})
    resp = app.post_json(url, POST_SUBSCRIPTIONS, status=200)
    assert resp.json['data']

@mock.patch('passerelle.contrib.meyzieu_newsletters.models.requests.get')
def test_update_empty_subscriptions(mock_get, setup):
    app, conn = setup
    response = mock.Mock()
    response.json.return_value = {}
    mock_get.return_value = response
    url = reverse('meyzieu-newsletters-subscriptions', kwargs={'slug': conn.slug})
    url += '?' + urlencode({'apikey': API_KEY, 'email': TEST_USER})
    resp = app.post_json(url, POST_SUBSCRIPTIONS, status=200)
    assert resp.json['data']

@mock.patch('passerelle.contrib.meyzieu_newsletters.models.requests.get',
            side_effect=mocked_requests_get)
def test_delete_subscriptions(mock_get, setup):
    app, conn = setup
    url = reverse('meyzieu-newsletters-subscriptions', kwargs={'slug': conn.slug})
    url += '?' + urlencode({'apikey': API_KEY, 'email': TEST_USER})
    resp = app.delete(url, status=200)
    assert resp.json['data']

@mock.patch('passerelle.contrib.meyzieu_newsletters.models.requests.get')
def test_delete_empty_subscriptions(mock_get, setup):
    app, conn = setup
    response = mock.Mock()
    response.json.return_value = {}
    mock_get.return_value = response
    url = reverse('meyzieu-newsletters-subscriptions', kwargs={'slug': conn.slug})
    url += '?' + urlencode({'apikey': API_KEY, 'email': TEST_USER})
    resp = app.delete(url, status=200)
    assert resp.json['data']

@mock.patch('passerelle.contrib.meyzieu_newsletters.models.requests.get',
            side_effect=set_subscriptions_connection_error)
def test_update_subscriptions_with_connection_error(mock_get, setup):
    app, conn = setup
    url = reverse('meyzieu-newsletters-subscriptions', kwargs={'slug': conn.slug})
    url += '?' + urlencode({'apikey': API_KEY, 'email': TEST_USER})
    resp = app.post_json(url, POST_SUBSCRIPTIONS, status=503)
    assert resp.json['err']
    assert resp.json['err_class'] == '%s.%s' % (SubscriptionsSetError.__module__,
                                                SubscriptionsSetError.__name__)
    assert resp.json['err_desc'] == 'error on setting subscriptions'
