import logging
import os
import re
from unittest import mock

import pytest
from django.utils.encoding import force_bytes, force_str
from django.utils.http import urlencode
from requests import Request
from requests.exceptions import ConnectionError

import tests.utils
from passerelle.apps.astregs.models import AstreGS, Link

BASE_URL = 'https://test-ws-astre-gs.departement06.fr/axis2/services/'


def get_xml_file(filename):
    filepath = os.path.join(os.path.dirname(__file__), 'data', 'astregs', filename)
    with open(filepath, 'rb') as f:
        return f.read()


def contact_search_side_effect(wsdl_url, **kwargs):
    if 'Tiers' in wsdl_url:
        response_content = get_xml_file('Tiers.xml')
    else:
        response_content = get_xml_file('Contact.xml')
    return mock.Mock(content=response_content, status_code=200, headers={'Content-Type': 'text/xml'})


def search_wsdl_side_effect(wsdl_url, **kwargs):
    if 'Tiers' in wsdl_url:
        response_content = get_xml_file('Tiers.wsdl')
    else:
        response_content = get_xml_file('Contact.wsdl')
    return mock.Mock(content=response_content, status_code=200, headers={'Content-Type': 'text/xml'})


def contact_wsdl_side_effect(wsdl_url, **kwargs):
    if 'ContactAdresses' in wsdl_url:
        response_content = get_xml_file('ContactAdresses.wsdl')
    else:
        response_content = get_xml_file('Contact.wsdl')
    return mock.Mock(content=response_content, status_code=200, headers={'Content-Type': 'text/xml'})


def contact_side_effect(wsdl_url, **kwargs):
    if 'ContactAdresses' in wsdl_url:
        response_content = get_xml_file('ContactAddressCreationResponse.xml')
    else:
        response_content = get_xml_file('ContactCreationResponse.xml')
    return mock.Mock(content=response_content, status_code=200, headers={'Content-Type': 'text/xml'})


@pytest.fixture
def connector(db):
    return tests.utils.make_resource(
        AstreGS,
        title='Test',
        slug='test',
        description='test',
        wsdl_base_url=BASE_URL,
        username='CS-FORML',
        password='secret',
        organism='CG06',
        budget='01',
        exercice='2019',
    )


@pytest.fixture
def recherche_tiers_details_wsdl():
    return get_xml_file('RechercheTiersDetails.wsdl')


@pytest.fixture
def recherche_tiers_details_result():
    return get_xml_file('RechercheTiersDetails.xml')


@pytest.fixture
def recherche_tiers_details_empty_result():
    content = get_xml_file('RechercheTiersDetails.xml')
    return force_bytes(re.sub('<ns1:liste>.*</ns1:liste>', '<ns1:liste></ns1:liste>', force_str(content)))


@pytest.fixture
def tiers_creation_response():
    return get_xml_file('TiersCreationResponse.xml')


@pytest.fixture
def tiers_with_no_siret_creation_response():
    return get_xml_file('TiersWithNoSiretCreationResponse.xml')


@pytest.fixture
def tiers_creation_error_response():
    return get_xml_file('TiersCreationErrorResponse.xml')


@pytest.fixture
def tiers_response():
    return get_xml_file('TiersResponse.xml')


@pytest.fixture
def tiers_error_response():
    return get_xml_file('TiersErrorResponse.xml')


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_search_association_by_siren(
    mocked_post, mocked_get, recherche_tiers_details_wsdl, recherche_tiers_details_result, connector, app
):
    mocked_get.return_value = mock.Mock(content=recherche_tiers_details_wsdl)
    mocked_post.return_value = mock.Mock(
        content=recherche_tiers_details_result, status_code=200, headers={'Content-Type': 'text/xml'}
    )
    resp = app.get('/astregs/test/associations', params={'siren': '500433909'})
    assert mocked_get.call_args[0][0] == '%sRechercheTiersDetails?wsdl' % BASE_URL
    assert mocked_post.call_args[0][0] == '%sRechercheTiersDetails/' % BASE_URL
    assert isinstance(resp.json['data'], list)
    assert len(resp.json['data']) > 0
    assert resp.json['data'][0]['id'] == '50043390900016'
    assert resp.json['data'][0]['text'] == '50043390900016 - ASSOCIATION OMNISPORTS DES MONTS D AZUR'
    assert resp.json['data'][0]['code'] == '173957'
    assert resp.json['data'][0]['name'] == 'ASSOCIATION OMNISPORTS DES MONTS D AZUR'


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_check_association_presence(mocked_post, mocked_get, connector, app):
    wsdl_content = get_xml_file('RechercheTiers.wsdl')
    response_content = get_xml_file('RechercheTiers.xml')
    mocked_get.return_value = mock.Mock(content=wsdl_content)
    mocked_post.return_value = mock.Mock(
        content=response_content, status_code=200, headers={'Content-Type': 'text/xml'}
    )
    resp = app.get('/astregs/test/check-association-by-siret', params={'siret': '50043390900014'})
    assert resp.json['exists'] is True
    response_content = get_xml_file('RechercheTiersNoResult.xml')
    mocked_post.return_value = mock.Mock(
        content=response_content, status_code=200, headers={'Content-Type': 'text/xml'}
    )
    resp = app.get('/astregs/test/check-association-by-siret', params={'siret': 'unknown'})
    assert resp.json['exists'] is False


@mock.patch('passerelle.utils.Request.get', side_effect=search_wsdl_side_effect)
@mock.patch('passerelle.utils.Request.post', side_effect=contact_search_side_effect)
def test_association_linking_means(mocked_post, mocked_get, client, connector, app):
    resp = app.get('/astregs/test/get-association-link-means', params={'association_id': '42'})
    assert resp.json['already_paired'] is False
    assert resp.json['data'] == [
        {
            'id': 'email',
            'text': 'par courriel vers fo***@***com',
            'value': 'foo@example.com',
            'type': 'email',
        },
        {'id': 'mobile', 'text': 'par SMS vers 06*****990', 'value': '0667788990', 'type': 'mobile'},
    ]
    assert resp.json['raw_data']['AdresseMail'] == 'foo@example.com'
    assert resp.json['raw_data']['TelephoneMobile'] == '06 67 78 89 90'

    Link.objects.create(name_id='user_name_id', association_id='42', resource=connector)
    resp = app.get(
        '/astregs/test/get-association-link-means', params={'association_id': '42', 'NameID': 'user_name_id'}
    )
    assert resp.json['already_paired'] is True

    for bad_mobile_number in ('', '01 43 35 01 35', '00 33 7 01 02 03 04', 'letters', '06 01 02'):
        mocked_post.side_effect = [
            mock.Mock(
                content=get_xml_file('Tiers.xml'), status_code=200, headers={'Content-Type': 'text/xml'}
            ),
            mock.Mock(
                content=get_xml_file('Contact.xml').replace(
                    b'<ns1:TelephoneMobile>06 67 78 89 90<',
                    b'<ns1:TelephoneMobile>%s<' % force_bytes(bad_mobile_number),
                ),
                status_code=200,
                headers={'Content-Type': 'text/xml'},
            ),
        ]
        resp = app.get('/astregs/test/get-association-link-means', params={'association_id': '42'})
        assert resp.json['data'] == [
            {
                'id': 'email',
                'text': 'par courriel vers fo***@***com',
                'value': 'foo@example.com',
                'type': 'email',
            }
        ]
        assert resp.json['raw_data']['AdresseMail'] == 'foo@example.com'
        assert resp.json['raw_data']['TelephoneMobile'] == (bad_mobile_number or None)


@mock.patch('passerelle.utils.Request.get', side_effect=search_wsdl_side_effect)
@mock.patch('passerelle.utils.Request.post', side_effect=contact_search_side_effect)
def test_link_user_to_association(
    mocked_post,
    mocked_get,
    client,
    recherche_tiers_details_wsdl,
    recherche_tiers_details_result,
    connector,
    app,
):
    assert Link.objects.count() == 0
    resp = app.get('/astregs/test/get-association-link-means', params={'association_id': '42'})
    assert len(resp.json['data']) == 2
    mocked_get.side_effect = None
    mocked_post.side_effect = None
    mocked_get.return_value = mock.Mock(content=recherche_tiers_details_wsdl)
    mocked_post.return_value = mock.Mock(
        content=recherche_tiers_details_result, status_code=200, headers={'Content-Type': 'text/xml'}
    )
    resp = app.get('/astregs/test/link', params={'association_id': '42', 'NameID': 'user_name_id'})
    assert Link.objects.filter(name_id='user_name_id', association_id='42').count() == 1
    link = Link.objects.get(name_id='user_name_id', association_id='42')
    assert link.association_label == '50043390900016 - ASSOCIATION OMNISPORTS DES MONTS D AZUR'
    assert resp.json['association_id'] == link.association_id
    assert resp.json['link'] == link.pk
    assert resp.json['created'] is True
    resp = app.get('/astregs/test/link', params={'association_id': '42', 'NameID': 'user_name_id'})
    assert resp.json['created'] is False


@mock.patch('passerelle.utils.Request.get', side_effect=search_wsdl_side_effect)
@mock.patch('passerelle.utils.Request.post', side_effect=contact_search_side_effect)
def test_unlink_user_from_association(
    mocked_post, mocked_get, connector, recherche_tiers_details_wsdl, recherche_tiers_details_result, app
):
    resp = app.get('/astregs/test/get-association-link-means', params={'association_id': '42'})
    mocked_get.side_effect = None
    mocked_post.side_effect = None
    mocked_get.return_value = mock.Mock(content=recherche_tiers_details_wsdl)
    mocked_post.return_value = mock.Mock(
        content=recherche_tiers_details_result, status_code=200, headers={'Content-Type': 'text/xml'}
    )
    resp = app.get('/astregs/test/link', params={'association_id': '42', 'NameID': 'user_name_id'})
    resp = app.get('/astregs/test/unlink', params={'NameID': 'user_name_id', 'association_id': '42'})
    assert resp.json['deleted']
    resp = app.get(
        '/astregs/test/unlink', params={'NameID': 'user_name_id', 'association_id': '42'}, status=404
    )


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_list_user_associations(
    mocked_post,
    mocked_get,
    recherche_tiers_details_wsdl,
    recherche_tiers_details_result,
    recherche_tiers_details_empty_result,
    connector,
    app,
    caplog,
):
    mocked_get.return_value = mock.Mock(content=recherche_tiers_details_wsdl)
    mocked_post.return_value = mock.Mock(
        content=recherche_tiers_details_result, status_code=200, headers={'Content-Type': 'text/xml'}
    )
    resp = app.get('/astregs/test/link', params={'association_id': '42', 'NameID': 'user_name_id'})
    resp = app.get('/astregs/test/links', params={'NameID': 'user_name_id'})
    mocked_get.assert_called()
    mocked_post.assert_called()
    assert resp.json['data']
    assert resp.json['data'][0]['id'] == '42'
    assert resp.json['data'][0]['text'] == '50043390900016 - ASSOCIATION OMNISPORTS DES MONTS D AZUR'

    mocked_post.return_value = mock.Mock(
        content=recherche_tiers_details_empty_result, status_code=200, headers={'Content-Type': 'text/xml'}
    )
    resp = app.get('/astregs/test/links', params={'NameID': 'user_name_id'})
    assert resp.json['data']
    assert resp.json['data'][0]['id'] == '42'
    assert resp.json['data'][0]['text'] == '50043390900016 - ASSOCIATION OMNISPORTS DES MONTS D AZUR'
    assert len(caplog.records)
    assert caplog.records[-1].levelno == logging.ERROR
    assert caplog.records[-1].message == 'No data found for association 42'


@mock.patch('passerelle.utils.Request.get', side_effect=search_wsdl_side_effect)
@mock.patch('passerelle.utils.Request.post')
def test_association_creation(
    mocked_post, mocked_get, tiers_creation_response, tiers_creation_error_response, connector, app
):
    payload = {
        'CodeFamille': '51',
        'CatTiers': '42',
        'EncodeKeyContact': '4242',
        'Sigle': 'EO',
        'NomEnregistrement': 'My association',
        'Organisme': 'CG06',
        'NumeroSiret': '112233445',
        'NumeroSiretFin': '00024',
        'StatutTiers': 'PROPOSE',
        'Type': '*',
        'AdresseTitre': 'AdressePrincipale',
        'AdresseLibelleRue': '169, rue du Château',
        'Financier': 'true',
        'AdresseIsAdresseDeFacturation': 'false',
        'AdresseIsAdresseDeCommande': 'false',
    }
    mocked_post.return_value = mock.Mock(
        content=tiers_creation_response, status_code=200, headers={'Content-Type': 'text/xml'}
    )
    resp = app.post_json('/astregs/test/create-association', params=payload)
    assert resp.json['data']
    data = resp.json['data']
    assert data['CodeTiers'] == '487464'
    assert data['CodeFamille'] == '51'
    assert data['CatTiers'] == '42'
    assert data['EncodeKeyContact'] == '4242'
    assert data['NomEnregistrement'] == 'My association'
    assert data['Organisme'] == 'CG06'
    assert data['NumeroSiret'] == '112233445'
    assert data['NumeroSiretFin'] == '00024'
    assert data['StatutTiers'] == 'PROPOSE'
    assert data['Type'] == '*'
    assert data['AdresseTitre'] == 'AdressePrincipale'
    assert data['AdresseLibelleRue'] == force_str('169, rue du Château')
    assert data['Sigle'] == 'EO'
    assert data['AdresseIsAdresseDeCommande'] == 'false'
    assert data['AdresseIsAdresseDeFacturation'] == 'false'

    mocked_post.return_value = mock.Mock(
        content=tiers_creation_error_response, status_code=500, headers={'Content-Type': 'text/xml'}
    )
    resp = app.post_json('/astregs/test/create-association', params=payload)
    assert resp.json['err'] == 1
    assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError'
    assert "Erreur technique dans le service 'Tiers'" in resp.json['err_desc']
    assert not resp.json['data']


@mock.patch('passerelle.utils.Request.get', side_effect=search_wsdl_side_effect)
@mock.patch('passerelle.utils.Request.post')
def test_tiers_creation(
    mocked_post,
    mocked_get,
    tiers_with_no_siret_creation_response,
    tiers_creation_error_response,
    connector,
    app,
):
    payload = {
        'CodeFamille': '51',
        'CatTiers': '42',
        'EncodeKeyContact': '4242',
        'Sigle': 'EO',
        'NomEnregistrement': 'MY TIERS',
        'Organisme': 'CG06',
        'StatutTiers': 'PROPOSE',
        'Type': '*',
        'AdresseTitre': 'AdressePrincipale',
        'AdresseLibelleRue': '169, rue du Château',
        'AdresseDestinataire': '169, rue du Château',
        'Financier': 'true',
        'AdresseIsAdresseDeFacturation': 'false',
        'AdresseIsAdresseDeCommande': 'false',
    }
    mocked_post.return_value = mock.Mock(
        content=tiers_with_no_siret_creation_response, status_code=200, headers={'Content-Type': 'text/xml'}
    )
    resp = app.post_json('/astregs/test/create-association', params=payload)
    assert resp.json['data']
    data = resp.json['data']
    assert data['CodeTiers'] == '492269'
    assert data['CodeFamille'] == '51'
    assert data['CatTiers'] == '42'
    assert data['EncodeKeyContact'] == '4242'
    assert data['NomEnregistrement'] == 'MY TIERS'
    assert data['StatutTiers'] == 'PROPOSE'


@mock.patch('passerelle.utils.Request.get', side_effect=search_wsdl_side_effect)
@mock.patch('passerelle.utils.Request.post')
def test_get_association_by_id(mocked_post, mocked_get, tiers_response, tiers_error_response, connector, app):
    mocked_post.return_value = mock.Mock(
        content=tiers_response, status_code=200, headers={'Content-Type': 'text/xml'}
    )

    resp = app.get('/astregs/test/get-association-by-id', params={'association_id': '487464'})
    assert resp.json['data']
    data = resp.json['data']
    assert data['CodeTiers'] == '487464'
    assert data['CodeFamille'] == '51'
    assert data['CatTiers'] == '42'
    assert data['NomEnregistrement'] == 'My association'
    assert data['Organisme'] == 'CG06'
    assert data['NumeroSiret'] == '112233445'
    assert data['NumeroSiretFin'] == '00024'
    assert data['StatutTiers'] == 'PROPOSE'

    resp = app.get(
        '/astregs/test/get-association-by-id',
        params={'association_id': '487464', 'NameID': 'user_name_id'},
        status=404,
    )

    Link.objects.create(name_id='user_name_id', association_id='487464', resource=connector)
    resp = app.get(
        '/astregs/test/get-association-by-id', params={'association_id': '487464', 'NameID': 'user_name_id'}
    )
    assert resp.json['data']
    mocked_post.return_value = mock.Mock(
        content=tiers_error_response, status_code=500, headers={'Content-Type': 'text/xml'}
    )
    resp = app.get('/astregs/test/get-association-by-id', params={'association_id': 'unknown'}, status=200)
    assert resp.json['err'] == 1
    assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError'
    assert "Erreur technique dans le service 'Tiers'" in resp.json['err_desc']
    assert not resp.json['data']


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_get_contact_details(mocked_post, mocked_get, connector, app):
    mocked_get.return_value = mock.Mock(content=get_xml_file('Contact.wsdl'))
    mocked_post.return_value = mock.Mock(
        content=get_xml_file('ContactResponse.xml'), status_code=200, headers={'Content-Type': 'text/xml'}
    )
    resp = app.get('/astregs/test/get-contact', params={'contact_id': '1111'})
    assert resp.json['err'] == 0
    assert resp.json['data']
    data = resp.json['data']
    assert data['idContact'] == '1111'
    assert data['CodeContact'] == 'POL14466'
    assert data['Nom'] == 'NARDELLI'
    assert data['Prenom'] == 'Robert'
    assert data['ComplementGeographique'] == 'Mairie'
    assert data['CodePostal'] == '06340'
    assert data['Ville'] == 'DRAP'
    assert data['LibellePays'] == 'France'

    mocked_post.return_value = mock.Mock(
        content=get_xml_file('ContactResponse.xml'), status_code=500, headers={'Content-Type': 'text/xml'}
    )
    resp = app.get('/astregs/test/get-contact', params={'contact_id': '4242'})
    assert not resp.json['data']
    assert resp.json['err'] == 1
    assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError'


@mock.patch('passerelle.utils.Request.get', side_effect=ConnectionError('mocked error', request=Request()))
@mock.patch('passerelle.utils.Request.post', side_effect=NotImplementedError)
def test_low_level_connection_error(
    mocked_post, mocked_get, tiers_response, tiers_error_response, connector, app
):
    resp = app.get('/astregs/test/get-association-by-id', params={'association_id': '487464'})
    assert resp.json['err'] == 1
    assert resp.json['data'] is None
    assert 'mocked error' in resp.json['err_desc']


@mock.patch('passerelle.utils.Request.get', side_effect=contact_wsdl_side_effect)
@mock.patch('passerelle.utils.Request.post', side_effect=contact_side_effect)
def test_create_association_contact(mocked_post, mocked_get, connector, app):
    payload = {
        'AdresseDestinataire': '169 rue du Ch\xc3\xa2teau',
        'Ville': 'Nice',
        'CodeContact': 'AS207002',
        'Commentaire': 'Contact creation',
        'country_code': 'FR',
        'AdresseMail': 'foo@example.com',
        'Prenom': 'Foo',
        'Nom': 'Bar',
        'TelephoneMobile': '0607080900',
        'TelephoneBureau': '0102030405',
        'CodeTitreCivilite': '035',
        'PageWeb': 'http://example.com',
        'CodePostal': '06000',
        'CodeFonction': '01',
        'EncodeKeyStatut': 'VALIDE',
    }
    resp = app.post_json('/astregs/test/create-contact', params=payload)
    assert resp.json['data']
    data = resp.json['data']
    assert data['idContact'] == '437309'
    assert data['Prenom'] == 'Foo'
    assert data['Nom'] == 'Bar'
    assert data['CodeFonction'] == '01'
    assert data['PageWeb'] == 'http://example.com'
    assert data['AdresseMail'] == 'foo@example.com'
    assert data['LibellePays'] == 'France'
    assert data['CodePays'] == 'FR'
    assert data['CodeTitreCivilite'] == '035'
    assert data['CodeContact'] == 'AS207002'
    assert data['TelephoneBureau'] == '0102030405'
    assert data['TelephoneMobile'] == '0607080900'


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_delete_association_contact(mocked_post, mocked_get, connector, app):
    mocked_get.return_value = mock.Mock(content=get_xml_file('Contact.wsdl'))
    mocked_post.return_value = mock.Mock(
        content=get_xml_file('ContactDeletionResponse.xml'),
        headers={'Content-Type': 'text/xml'},
        status_code=200,
    )
    resp = app.get('/astregs/test/delete-contact', params={'contact_id': '437307'})
    assert resp.json['data']
    # if contact is deleted the its id is None
    assert resp.json['data']['idContact'] is None


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_create_document(mocked_post, mocked_get, connector, app):
    mocked_get.return_value = mock.Mock(content=get_xml_file('DocumentAnnexe.wsdl'))
    mocked_post.return_value = mock.Mock(
        content=get_xml_file('DocumentCreationResponse.xml'),
        headers={'Content-Type': 'text/xml'},
        status_code=200,
    )
    payload = {
        'Sujet': 'Test',
        'Entite': 'COMMANDE',
        'CodType': 'COMMANDE',
        'Type': 'Type label',
        'hdnCodeTrt': 'UPDATE',
        'EncodeKeyEntite': '|25901|',
        'CodeDomaine': 'GF',
        'CodDom': 'GF',
        'Metadonnees': '|Organisme *CG06|Code Tiers *1|',
        'document': {
            'filename': 'test.pdf',
            'content_type': 'application/pdf',
            'content': 'base64encodedcontent',
        },
    }
    resp = app.post_json('/astregs/test/create-document', params=payload)
    assert resp.json['data']
    assert resp.json['data']['RefDocument'] == '111'
    assert resp.json['data']['NumVersion'] == '1'


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_create_grant_demand(mocked_post, mocked_get, connector, app):
    mocked_get.return_value = mock.Mock(content=get_xml_file('Dossier.wsdl'))
    mocked_post.return_value = mock.Mock(
        content=get_xml_file('DossierCreationResponse.xml'),
        headers={'Content-Type': 'text/xml'},
        status_code=200,
    )
    payload = {
        'Libelle': 'test grant demand',
        'LibelleCourt': 'test',
        'ModGestion': '1',
        'TypeAide': 'F',
        'Sens': 'D',
        'CodeTiersDem': '487473',
        'CodeServiceGestionnaire': 'SGG',
        'CodeAide': '030105',
        'CodeServiceUtilisateur': '030105',
    }
    resp = app.post_json('/astregs/test/create-grant-demand', params=payload)
    assert resp.json['data']
    data = resp.json['data']
    assert data['CodeDossier'] == '2019_06407'
    assert data['Exercice'] == '2019'
    assert data['Libelle'] == 'test grant demand'
    assert data['LibelleCourt'] == 'test'
    assert data['ModGestion'] == '1'
    assert data['CodeServiceGestionnaire'] == 'SGG'
    assert data['CodeServiceUtilisateur'] == 'SUG4'
    assert data['LibelleServiceUtilisateur'] == 'SPORTS ET JEUNESSE'
    assert data['TypeAide'] == 'F'
    assert data['CodeAide'] == '030105'
    assert data['LibelleAide'] == 'Actions culturelles - Etab publics locaux'
    assert data['Sens'] == 'D'
    assert data['CodeTiersDem'] == '487463'
    assert data['NomTiersDem'] == 'My Tiers'
    assert data['CodeStatut'] == 'ENR'
    assert data['DateCreation'] == '11/07/2019'


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_create_indana_indicator(mocked_post, mocked_get, connector, app):
    mocked_get.return_value = mock.Mock(content=get_xml_file('DossierIndicateur.wsdl'))
    mocked_post.return_value = mock.Mock(
        content=get_xml_file('DossierIndicateurCreationResponse.xml'),
        headers={'Content-Type': 'text/xml'},
        status_code=200,
    )
    payload = {'CodeDossier': '2019_06407', 'CodeInd_1': '501', 'AnneeInd_1': '2019', 'ValInd_1': 'O'}
    resp = app.post_json('/astregs/test/create-indana-indicator', params=payload)
    assert resp.json['err'] == 0
    assert resp.json['data']
    data = resp.json['data']
    assert data['CodeDossier'] == '2019_06407'
    assert data['CodeInd_1'] == '501'
    assert data['AnneeInd_1'] == '2019'
    assert data['ValInd_1'] == 'O'
    assert data['IndAide'] == 'Non'


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_update_indana_indicator(mocked_post, mocked_get, connector, app):
    mocked_get.return_value = mock.Mock(content=get_xml_file('DossierIndicateur.wsdl'))
    mocked_post.return_value = mock.Mock(
        content=get_xml_file('DossierIndicateurModificationResponse.xml'),
        headers={'Content-Type': 'text/xml'},
        status_code=200,
    )
    payload = {'CodeDossier': '2019_06407', 'CodeInd_1': '501', 'AnneeInd_1': '2019', 'ValInd_1': 'N'}
    resp = app.post_json('/astregs/test/update-indana-indicator', params=payload)
    assert resp.json == {
        'err': 0,
        'data': {
            'CodeDossier': '2019_06407',
            'CodeInd_1': '501',
            'AnneeInd_1': '2019',
            'ValInd_1': 'N',
            'IndAide': 'Non',
        },
    }


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_delete_indana_indicator(mocked_post, mocked_get, connector, app):
    mocked_get.return_value = mock.Mock(content=get_xml_file('DossierIndicateur.wsdl'))
    mocked_post.return_value = mock.Mock(
        content=get_xml_file('DossierIndicateurSuppressionResponse.xml'),
        headers={'Content-Type': 'text/xml'},
        status_code=200,
    )
    payload = {'CodeDossier': '2019_06407', 'CodeInd_1': '501', 'AnneeInd_1': '2019'}
    resp = app.post_json('/astregs/test/delete-indana-indicator', params=payload)
    assert resp.json == {
        'err': 0,
        'data': {
            'CodeDossier': '2019_06407',
            'CodeInd_1': '501',
            'AnneeInd_1': '2019',
            'ValInd_1': 'N',
            'IndAide': 'Non',
        },
    }


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_create_tiers_rib(mocked_post, mocked_get, connector, app):
    mocked_get.return_value = mock.Mock(content=get_xml_file('TiersRib.wsdl'))
    mocked_post.return_value = mock.Mock(
        content=get_xml_file('TiersRibCreationResponse.xml'),
        headers={'Content-Type': 'text/xml'},
        status_code=200,
    )
    payload = {
        'CleIban': '76',
        'CodeBic': 'CODEBIC',
        'CodeDevise': 'EUR',
        'CodeIso2Pays': 'FR',
        'CodePaiement': '3',
        'CodeStatut': 'PROPOSE',
        'CodeTiers': '487464',
        'LibelleCompteEtranger': 'LABEL',
        'LibelleCourt': 'Test',
        'LibellePays': 'FR',
        'NumeroIban': 'FR76AABBCCDDEEFFGGHHIIJJKKLLM',
        'CodeDomiciliation': '1',
    }

    resp = app.post_json('/astregs/test/create-tiers-rib', params=payload)
    assert resp.json['err'] == 0
    assert resp.json['data']
    data = resp.json['data']

    assert data['IdRib'] == '621410'
    assert data['CodeDomiciliation'] == '5'
    assert data['LibelleGuichet'] == 'GUICHET'
    assert data['NumeroIban'] == 'FR76 AA BB CC DD EE FF GG HH II JJ KK LLM'
    assert data['CompteEtranger'] == 'AABBCCDDEEFFGGHHIIJJKKLLM'
    assert data['LibelleDevise'] == 'Euros'
    assert data['LibellePays'] == 'France'


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_get_tiers_rib(mocked_post, mocked_get, connector, app):
    mocked_get.return_value = mock.Mock(content=get_xml_file('TiersRib.wsdl'))
    mocked_post.return_value = mock.Mock(
        content=get_xml_file('TiersRibChargementResponse.xml'),
        headers={'Content-Type': 'text/xml'},
        status_code=200,
    )
    params = {'CodeTiers': '487464', 'IdRib': '621407'}

    resp = app.get('/astregs/test/get-tiers-rib', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data']
    data = resp.json['data']

    assert data['IdRib'] == '621407'
    assert data['LibelleCourt'] == 'Test'
    assert data['CodeDomiciliation'] == '2'
    assert data['CodeBic'] == 'BIC'
    assert data['LibelleGuichet'] == 'GUICHET'
    assert data['NumeroIban'] == 'FR76 AA BB CC DD EE FF GG HH II JJ KK LLM'


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_update_tiers_rib(mocked_post, mocked_get, connector, app):
    mocked_get.return_value = mock.Mock(content=get_xml_file('TiersRib.wsdl'))
    mocked_post.return_value = mock.Mock(
        content=get_xml_file('TiersRibModificationResponse.xml'),
        headers={'Content-Type': 'text/xml'},
        status_code=200,
    )
    payload = {
        'CleIban': '76',
        'CodeBic': 'CODEBIC',
        'CodeDevise': 'EUR',
        'CodeIso2Pays': 'FR',
        'CodePaiement': '3',
        'CodeStatut': 'PROPOSE',
        'CodeTiers': '487464',
        'CodeDomiciliation': '1',
        'LibelleCompteEtranger': 'LABEL',
        'LibelleCourt': 'New Test',
        'LibellePays': 'FR',
        'NumeroIban': 'FR76AABBCCDDEEFFGGHHIIJJKKLLM',
    }

    qs = urlencode({'CodeTiers': '487464', 'IdRib': '621412'})

    resp = app.post_json('/astregs/test/update-tiers-rib?%s' % qs, params=payload)
    assert resp.json['err'] == 0
    assert resp.json['data']
    data = resp.json['data']

    assert data['LibelleCourt'] == 'New Test'


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_delete_tiers_rib(mocked_post, mocked_get, connector, app):
    mocked_get.return_value = mock.Mock(content=get_xml_file('TiersRib.wsdl'))
    mocked_post.return_value = mock.Mock(
        content=get_xml_file('TiersRibSuppressionResponse.xml'),
        headers={'Content-Type': 'text/xml'},
        status_code=200,
    )

    params = {'CodeTiers': '487464', 'IdRib': '621407'}

    resp = app.get('/astregs/test/delete-tiers-rib', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data']
    data = resp.json['data']

    assert data['IdRib'] is None
    assert data['CleRib'] is None
    assert data['CodeBic'] is None
    assert data['CleIban'] is None


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_search_tiers_by_rib(mocked_post, mocked_get, connector, app):
    mocked_get.return_value = mock.Mock(content=get_xml_file('RechercheTiers.wsdl'))
    mocked_post.return_value = mock.Mock(
        content=get_xml_file('RechercheTiersByRibResponse.xml'),
        headers={'Content-Type': 'text/xml'},
        status_code=200,
    )
    params = {'banque': '30001', 'guichet': '00794', 'numero_compte': '12345678901', 'cle': '85'}

    resp = app.get('/astregs/test/find-tiers-by-rib', params=params)
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 2
    for item in resp.json['data']:
        assert 'id' in item
        assert 'text' in item
        assert '487464' in item['text'] or '144984' in item['text']


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_search_tiers_by_rib_no_result(mocked_post, mocked_get, connector, app):
    mocked_get.return_value = mock.Mock(content=get_xml_file('RechercheTiers.wsdl'))
    mocked_post.return_value = mock.Mock(
        content=get_xml_file('RechercheTiersByRibEmptyResponse.xml'),
        headers={'Content-Type': 'text/xml'},
        status_code=200,
    )
    params = {'banque': '30001', 'guichet': '00794', 'numero_compte': '12345678901', 'cle': '85'}

    resp = app.get('/astregs/test/find-tiers-by-rib', params=params)
    assert resp.json['err'] == 0
    assert len(resp.json['data']) == 0


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_get_dossier(mocked_post, mocked_get, connector, app):
    mocked_get.return_value = mock.Mock(content=get_xml_file('Dossier.wsdl'))
    mocked_post.return_value = mock.Mock(
        content=get_xml_file('DossierResponse.xml'),
        headers={'Content-Type': 'text/xml'},
        status_code=200,
    )
    params = {'CodeDossier': '2021-1234'}

    resp = app.get('/astregs/test/get-dossier', params=params)
    assert resp.json['err'] == 0
    assert resp.json['data']
    data = resp.json['data']
    assert data['Libelle'] == 'Libelle'
    assert data['LibelleCourt'] == 'Libelle court'
    assert data['CodeStatut'] == 'VOT'


@mock.patch('passerelle.apps.astregs.models.serialize_object')
def test_context_overloading(mocked_serialize_object, connector, app, monkeypatch):
    mock_operation_result = mock.Mock(liste=False, EncodeKeyContact=False)
    mock_operation = mock.Mock(return_value=mock_operation_result)

    class MockService:
        def __getattr__(self, name):
            return mock_operation

    def mock_get_client(*args, **kwargs):
        return mock.Mock(service=MockService())

    monkeypatch.setattr(AstreGS, 'get_client', mock_get_client)
    expected_context = {'Organisme': 'foo', 'Budget': 'bar', 'Exercice': 'baz'}

    assert not mock_operation.call_args
    app.get(
        '/astregs/test/associations',
        params={'siren': '50043390900014', 'organism': 'foo', 'budget': 'bar', 'exercice': 'baz'},
    )
    assert mock_operation.call_args.kwargs['Contexte'] == expected_context
    mock_operation.reset_mock()

    # do it a second time on the same endpoints without context parameters
    assert not mock_operation.call_args
    app.get('/astregs/test/associations', params={'siren': '50043390900014'})
    assert mock_operation.call_args.kwargs['Contexte'] == {
        'Organisme': 'CG06',
        'Budget': '01',
        'Exercice': '2019',
    }
    mock_operation.reset_mock()

    assert not mock_operation.call_args
    app.get(
        '/astregs/test/check-association-by-siret',
        params={'siret': '50043390900014', 'organism': 'foo', 'budget': 'bar', 'exercice': 'baz'},
    )
    assert mock_operation.call_args.kwargs['Contexte'] == expected_context
    mock_operation.reset_mock()

    assert not mock_operation.call_args
    app.get(
        '/astregs/test/get-association-link-means',
        params={'association_id': '1', 'NameID': '1', 'organism': 'foo', 'budget': 'bar', 'exercice': 'baz'},
    )
    assert mock_operation.call_args.args[0]['Contexte'] == expected_context
    mock_operation.reset_mock()

    assert not mock_operation.call_args
    link = Link.objects.create(name_id='1', association_id='1', resource=connector)
    mocked_serialize_object.configure_mock(return_value=[])
    app.get(
        '/astregs/test/get-association-by-id',
        params={'association_id': '1', 'NameID': '1', 'organism': 'foo', 'budget': 'bar', 'exercice': 'baz'},
    )
    assert mock_operation.call_args.args[0]['Contexte'] == expected_context
    link.delete()
    mock_operation.reset_mock()
    mocked_serialize_object.reset_mock()

    assert not mock_operation.call_args
    mocked_serialize_object.configure_mock(return_value=[])
    app.post_json(
        '/astregs/test/create-association',
        params={
            'CodeFamille': '51',
            'CatTiers': '42',
            'EncodeKeyContact': '4242',
            'Sigle': 'EO',
            'NomEnregistrement': 'My association',
            'Organisme': 'CG06',
            'NumeroSiret': '112233445',
            'NumeroSiretFin': '00024',
            'StatutTiers': 'PROPOSE',
            'Type': '*',
            'AdresseTitre': 'AdressePrincipale',
            'AdresseLibelleRue': '169, rue du Château',
            'Financier': 'true',
            'AdresseIsAdresseDeFacturation': 'false',
            'AdresseIsAdresseDeCommande': 'false',
            'organism': 'foo',
            'budget': 'bar',
            'exercice': 'baz',
        },
    )
    assert mock_operation.call_args.args[0]['Contexte'] == expected_context
    mock_operation.reset_mock()
    mocked_serialize_object.reset_mock()

    assert not mock_operation.call_args
    mocked_serialize_object.configure_mock(return_value=[])
    app.get(
        '/astregs/test/get-contact',
        params={'contact_id': '1', 'organism': 'foo', 'budget': 'bar', 'exercice': 'baz'},
    )
    assert mock_operation.call_args.args[0]['Contexte'] == expected_context
    mock_operation.reset_mock()
    mocked_serialize_object.reset_mock()

    assert not mock_operation.call_args
    mocked_serialize_object.configure_mock(return_value=[])
    app.post_json(
        '/astregs/test/create-contact',
        params={
            'AdresseDestinataire': '169 rue du Ch\xc3\xa2teau',
            'Ville': 'Nice',
            'CodeContact': 'AS207002',
            'Commentaire': 'Contact creation',
            'country_code': 'FR',
            'AdresseMail': 'foo@example.com',
            'Prenom': 'Foo',
            'Nom': 'Bar',
            'TelephoneMobile': '0607080900',
            'TelephoneBureau': '0102030405',
            'CodeTitreCivilite': '035',
            'PageWeb': 'http://example.com',
            'CodePostal': '06000',
            'CodeFonction': '01',
            'EncodeKeyStatut': 'VALIDE',
            'organism': 'foo',
            'budget': 'bar',
            'exercice': 'baz',
        },
    )
    assert mock_operation.call_args.args[0]['Contexte'] == expected_context
    mock_operation.reset_mock()
    mocked_serialize_object.reset_mock()

    assert not mock_operation.call_args
    mocked_serialize_object.configure_mock(return_value=[])
    app.get(
        '/astregs/test/delete-contact',
        params={'contact_id': '1', 'organism': 'foo', 'budget': 'bar', 'exercice': 'baz'},
    )
    assert mock_operation.call_args.args[0]['Contexte'] == expected_context
    mock_operation.reset_mock()
    mocked_serialize_object.reset_mock()

    assert not mock_operation.call_args
    mocked_serialize_object.configure_mock(return_value=[])
    app.post_json(
        '/astregs/test/create-document',
        params={
            'Sujet': 'Test',
            'Entite': 'COMMANDE',
            'CodType': 'COMMANDE',
            'Type': 'Type label',
            'hdnCodeTrt': 'UPDATE',
            'EncodeKeyEntite': '|25901|',
            'CodeDomaine': 'GF',
            'CodDom': 'GF',
            'Metadonnees': '|Organisme *CG06|Code Tiers *1|',
            'document': {
                'filename': 'test.pdf',
                'content_type': 'application/pdf',
                'content': 'base64encodedcontent',
            },
            'organism': 'foo',
            'budget': 'bar',
            'exercice': 'baz',
        },
    )
    assert mock_operation.call_args.args[0]['Contexte'] == expected_context
    mock_operation.reset_mock()
    mocked_serialize_object.reset_mock()

    assert not mock_operation.call_args
    mocked_serialize_object.configure_mock(return_value=[])
    app.post_json(
        '/astregs/test/create-grant-demand',
        params={
            'Libelle': 'test grant demand',
            'LibelleCourt': 'test',
            'ModGestion': '1',
            'TypeAide': 'F',
            'Sens': 'D',
            'CodeTiersDem': '487473',
            'CodeServiceGestionnaire': 'SGG',
            'CodeAide': '030105',
            'CodeServiceUtilisateur': '030105',
            'organism': 'foo',
            'budget': 'bar',
            'exercice': 'baz',
        },
    )
    assert mock_operation.call_args.args[0]['Contexte'] == expected_context
    mock_operation.reset_mock()
    mocked_serialize_object.reset_mock()

    assert not mock_operation.call_args
    mocked_serialize_object.configure_mock(return_value=[])
    app.post_json(
        '/astregs/test/create-indana-indicator',
        params={
            'CodeDossier': '2019_06407',
            'CodeInd_1': '501',
            'AnneeInd_1': '2019',
            'ValInd_1': 'O',
            'organism': 'foo',
            'budget': 'bar',
            'exercice': 'baz',
        },
    )
    assert mock_operation.call_args.args[0]['Contexte'] == expected_context
    mock_operation.reset_mock()
    mocked_serialize_object.reset_mock()

    assert not mock_operation.call_args
    mocked_serialize_object.configure_mock(return_value=[])
    app.post_json(
        '/astregs/test/update-indana-indicator',
        params={
            'CodeDossier': '2019_06407',
            'CodeInd_1': '501',
            'AnneeInd_1': '2019',
            'ValInd_1': 'N',
            'organism': 'foo',
            'budget': 'bar',
            'exercice': 'baz',
        },
    )
    assert mock_operation.call_args.args[0]['Contexte'] == expected_context
    mock_operation.reset_mock()
    mocked_serialize_object.reset_mock()

    assert not mock_operation.call_args
    mocked_serialize_object.configure_mock(return_value=[])
    app.post_json(
        '/astregs/test/delete-indana-indicator',
        params={
            'CodeDossier': '2019_06407',
            'CodeInd_1': '501',
            'AnneeInd_1': '2019',
            'organism': 'foo',
            'budget': 'bar',
            'exercice': 'baz',
        },
    )
    assert mock_operation.call_args.args[0]['Contexte'] == expected_context
    mock_operation.reset_mock()
    mocked_serialize_object.reset_mock()

    assert not mock_operation.call_args
    mocked_serialize_object.configure_mock(return_value=[])
    app.post_json(
        '/astregs/test/create-tiers-rib',
        params={
            'CleIban': '76',
            'CodeBic': 'CODEBIC',
            'CodeDevise': 'EUR',
            'CodeIso2Pays': 'FR',
            'CodePaiement': '3',
            'CodeStatut': 'PROPOSE',
            'CodeTiers': '487464',
            'LibelleCompteEtranger': 'LABEL',
            'LibelleCourt': 'Test',
            'LibellePays': 'FR',
            'NumeroIban': 'FR76AABBCCDDEEFFGGHHIIJJKKLLM',
            'CodeDomiciliation': '1',
            'organism': 'foo',
            'budget': 'bar',
            'exercice': 'baz',
        },
    )
    assert mock_operation.call_args.args[0]['Contexte'] == expected_context
    mock_operation.reset_mock()
    mocked_serialize_object.reset_mock()

    assert not mock_operation.call_args
    mocked_serialize_object.configure_mock(return_value=[])
    app.get(
        '/astregs/test/get-tiers-rib',
        params={
            'CodeTiers': '487464',
            'IdRib': '621407',
            'organism': 'foo',
            'budget': 'bar',
            'exercice': 'baz',
        },
    )
    assert mock_operation.call_args.args[0]['Contexte'] == expected_context
    mock_operation.reset_mock()
    mocked_serialize_object.reset_mock()

    assert not mock_operation.call_args
    mocked_serialize_object.configure_mock(return_value=[])
    qs = urlencode({'CodeTiers': '487464', 'IdRib': '621412'})
    app.post_json(
        '/astregs/test/update-tiers-rib?%s' % qs,
        params={
            'CleIban': '76',
            'CodeBic': 'CODEBIC',
            'CodeDevise': 'EUR',
            'CodeIso2Pays': 'FR',
            'CodePaiement': '3',
            'CodeStatut': 'PROPOSE',
            'CodeTiers': '487464',
            'CodeDomiciliation': '1',
            'LibelleCompteEtranger': 'LABEL',
            'LibelleCourt': 'New Test',
            'LibellePays': 'FR',
            'NumeroIban': 'FR76AABBCCDDEEFFGGHHIIJJKKLLM',
            'organism': 'foo',
            'budget': 'bar',
            'exercice': 'baz',
        },
    )
    assert mock_operation.call_args.args[0]['Contexte'] == expected_context
    mock_operation.reset_mock()
    mocked_serialize_object.reset_mock()

    assert not mock_operation.call_args
    mocked_serialize_object.configure_mock(return_value=[])
    app.get(
        '/astregs/test/delete-tiers-rib',
        params={
            'CodeTiers': '487464',
            'IdRib': '621407',
            'organism': 'foo',
            'budget': 'bar',
            'exercice': 'baz',
        },
    )
    assert mock_operation.call_args.args[0]['Contexte'] == expected_context
    mock_operation.reset_mock()
    mocked_serialize_object.reset_mock()

    assert not mock_operation.call_args
    mocked_serialize_object.configure_mock(return_value=[])
    app.get(
        '/astregs/test/find-tiers-by-rib',
        params={
            'banque': '30001',
            'guichet': '00794',
            'numero_compte': '12345678901',
            'cle': '85',
            'organism': 'foo',
            'budget': 'bar',
            'exercice': 'baz',
        },
    )
    assert mock_operation.call_args.kwargs['Contexte'] == expected_context
    mock_operation.reset_mock()
    mocked_serialize_object.reset_mock()

    assert not mock_operation.call_args
    mocked_serialize_object.configure_mock(return_value=[])
    app.get(
        '/astregs/test/link',
        params={
            'association_id': '42',
            'NameID': 'user_name_id',
            'organism': 'foo',
            'budget': 'bar',
            'exercice': 'baz',
        },
    )
    assert mock_operation.call_args.kwargs['Contexte'] == expected_context
    mock_operation.reset_mock()
    mocked_serialize_object.reset_mock()

    assert not mock_operation.call_args
    mocked_serialize_object.configure_mock(return_value=[])
    app.get(
        '/astregs/test/links',
        params={
            'NameID': 'user_name_id',
            'organism': 'foo',
            'budget': 'bar',
            'exercice': 'baz',
        },
    )
    assert mock_operation.call_args.kwargs['Contexte'] == expected_context
    mock_operation.reset_mock()
    mocked_serialize_object.reset_mock()
