import copy
import json
import os
from decimal import Decimal
from unittest import mock

import pytest
from django.contrib.contenttypes.models import ContentType
from django.urls import reverse

from passerelle.base.models import AccessRight, ApiUser
from passerelle.contrib.solis_apa import integration
from passerelle.contrib.solis_apa.models import SolisAPA

TEST_BASE_DIR = os.path.join(os.path.dirname(__file__), 'data', 'solis_apa')


def json_get_data(filename):
    with open(os.path.join(TEST_BASE_DIR, filename)) as fd:
        return json.load(fd)


@pytest.fixture
def setup(db):
    api = ApiUser.objects.create(username='all', keytype='', key='')
    solis = SolisAPA.objects.create(base_url='https://whateever.com/rec/', slug='test')
    obj_type = ContentType.objects.get_for_model(solis)
    AccessRight.objects.create(
        codename='can_access', apiuser=api, resource_type=obj_type, resource_pk=solis.pk
    )


@pytest.fixture
def url():
    def get_url(name):
        return reverse('solis-apa-%s' % name, kwargs={'slug': 'test'})

    return get_url


@pytest.fixture(
    params=[
        json_get_data('premiere_demande_apa_domicile.json'),
        json_get_data('premiere_demande_apa_etablissement.json'),
        json_get_data('premiere_demande_apa_etablissement_papier.json'),
    ]
)
def formdata(request):
    return request.param


@mock.patch('passerelle.utils.Request.post')
def test_suivi_error(mocked_post, setup, app):
    mocked_post.return_value = mock.Mock(status_code=500)

    resp = app.get(reverse('solis-apa-suivi', kwargs={'slug': 'test', 'suivi_type': 'visite'}))
    assert resp.json['err_desc'] == "suivi visite ws: error code 500"
    assert resp.json['err'] == 1


@mock.patch('passerelle.utils.Request.post')
def test_instegration_demande_apa_domicile(mocked_post, setup, app, url):
    fake_response = (
        '{"ImportIdResults":{"Items":[{"key":"indexDossier","value":359043},'
        '{"key":"indexBeneficiaire","value":458238},{"key":"indexDemande","value":221155}]}}'
    )

    mocked_post.return_value = mock.Mock(
        status_code=200, content=fake_response, json=lambda: json.loads(fake_response)
    )

    params = json_get_data('premiere_demande_apa_domicile.json')
    resp = app.post_json(url('integration'), params=params, status=200)
    assert resp.json['data']['indexDossier'] == 359043
    assert resp.json['data']['indexBeneficiaire'] == 458238
    assert resp.json['data']['indexDemande'] == 221155

    params['fields']['anneerefrevenu'] = None
    resp = app.post_json(url('integration'), params=params, status=200)
    assert resp.json['data']['indexDossier'] == 359043
    assert resp.json['data']['indexBeneficiaire'] == 458238
    assert resp.json['data']['indexDemande'] == 221155


@mock.patch('passerelle.utils.Request.post')
def test_integration_demande_apa_etablissement(mocked_post, setup, app, url):
    fake_response = (
        '{"ImportIdResults":{"Items":[{"key":"indexDossier","value":359043},'
        '{"key":"indexBeneficiaire","value":458238},{"key":"indexDemande","value":221155}]}}'
    )

    mocked_post.return_value = mock.Mock(
        status_code=200, content=fake_response, json=lambda: json.loads(fake_response)
    )

    resp = app.post_json(
        url('integration'), params=json_get_data('premiere_demande_apa_etablissement.json'), status=200
    )

    assert resp.json['data']['indexDossier'] == 359043
    assert resp.json['data']['indexBeneficiaire'] == 458238
    assert resp.json['data']['indexDemande'] == 221155


@mock.patch('passerelle.utils.Request.post')
def test_integration_error(mocked_post, setup, app, url):
    mocked_post.return_value = mock.Mock(status_code=500)
    resp = app.post_json(url('integration'), params=json_get_data('premiere_demande_apa_etablissement.json'))
    assert resp.json['err_desc'] == "integration ws: error code 500"
    assert resp.json['err'] == 1


def test_get_conjoint(setup, url, formdata):
    data = integration.build_message(formdata)
    if formdata['display_id'] == '25-3':
        assert data['Conjoint']['indexIndividu'] == '458107'
        assert data['Conjoint']['bParticipeRevenus'] is False
        assert data['Conjoint']['dateNaissance'] == '1930-06-11'
        assert data['Conjoint']['nom'] == 'MCBEAL'
        assert data['Conjoint']['prenom'] == 'ALLY'
        assert data['Conjoint']['sexe'] == 'F'
        assert data['Conjoint']['situationFamiliale'] == 2
        assert data['RevenusImposition']['anneeReference'] == 2015
        assert Decimal(data['RevenusImposition']['revenuReference']) == Decimal(30000.0)
    elif formdata['display_id'] == '32-1':
        assert 'Conjoint' not in data
        assert data['RevenusImposition']['anneeReference'] == 2015
        assert Decimal(data['RevenusImposition']['revenuReference']) == Decimal(32000.0)
    else:
        assert 'Conjoint' not in data
        assert data['RevenusImposition']['anneeReference'] == 2016
        assert Decimal(data['RevenusImposition']['revenuReference']) == Decimal(1500)


def test_recipient_address(setup, formdata):
    data = integration.build_message(formdata)
    if formdata['display_id'] == '25-3':
        # received values
        assert formdata['workflow']['data']['adresse_var_code_commune'] == '14000 CAEN'
        assert formdata['workflow']['data']['adresse_var_code_commune_raw'] == 'commune-14-118'
        assert formdata['workflow']['data']['adresse_var_code_lieu'] == 'AVENUE DU PARC BELLEVUE'
        assert formdata['workflow']['data']['adresse_var_code_lieu_raw'] == '0867'
        assert formdata['workflow']['data']['adresse_var_num_lieu'] == '1'
        assert formdata['fields']['code_commune'] == '14000 CAEN'
        assert formdata['fields']['code_commune_raw'] == 'commune-14-118'
        # built values
        assert data['Beneficiaire']['Adresse']['codeCommune'] == 118
        assert data['Beneficiaire']['Adresse']['codeDepartement'] == 14
        assert data['Beneficiaire']['Adresse']['codeLieu'] == '0867'
        assert data['Beneficiaire']['Adresse']['numeroLieu'] == '1'
    elif formdata['display_id'] == '32-1':
        # received values
        assert formdata['workflow']['data']['adresse_var_code_commune'] == '14930 ETERVILLE'
        assert formdata['workflow']['data']['adresse_var_code_commune_raw'] == 'commune-14-254'
        assert formdata['workflow']['data']['adresse_var_code_lieu'] == 'RUE DU JARDIN DE LA FERME'
        assert formdata['workflow']['data']['adresse_var_code_lieu_raw'] == 'Z001'
        assert formdata['workflow']['data']['adresse_var_num_lieu'] == '1'
        assert formdata['fields']['code_commune'] == '14930 ETERVILLE'
        assert formdata['fields']['code_commune_raw'] == 'commune-14-254'
        # built values
        assert data['Beneficiaire']['Adresse']['codeCommune'] == 254
        assert data['Beneficiaire']['Adresse']['codeDepartement'] == 14
        assert data['Beneficiaire']['Adresse']['codeLieu'] == 'Z001'
        assert data['Beneficiaire']['Adresse']['numeroLieu'] == '1'
    else:
        # received values
        assert formdata['fields']['papier_code_commune'] == '33370 FARGUES ST HILAIRE'
        assert formdata['fields']['papier_code_commune_raw'] == 'commune-33-165'
        assert formdata['fields']['papier_code_lieu'] == 'ROUTE DE MAISON ROUGE'
        assert formdata['fields']['papier_code_lieu_raw'] == '0001'
        assert formdata['fields']['papier_excode_commune'] == '14150 OUISTREHAM'
        assert formdata['fields']['papier_excode_commune_raw'] == 'commune-14-488'
        assert formdata['fields']['papier_excode_lieu'] == 'RUE DU PETIT BONHEUR'
        assert formdata['fields']['papier_excode_lieu_raw'] == '0730'
        assert formdata['fields']['papier_exnum_lieu'] == '2'
        assert formdata['fields']['papier_num_lieu'] == '20'
        # built values
        assert data['Beneficiaire']['Adresse']['codeCommune'] == 488
        assert data['Beneficiaire']['Adresse']['codeDepartement'] == 14
        assert data['Beneficiaire']['Adresse']['codeLieu'] == '0730'
        assert data['Beneficiaire']['Adresse']['numeroLieu'] == '2'


def test_missing_field(setup, formdata):
    data = integration.build_message(formdata)
    assert 'lieuNaissance' in data['Beneficiaire']
    partial_formdata = copy.deepcopy(formdata)
    partial_formdata['fields'].pop('lieunbeneficiaire')
    data = integration.build_message(partial_formdata)
    assert 'lieuNaissance' not in data['Beneficiaire']
