# Passerelle - uniform access to data and services
# Copyright (C) 2021 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; exclude 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.deepcopy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import json
from urllib.parse import parse_qs, urlparse, urlunparse

import pytest
from django.utils.timezone import now

import tests.utils
from passerelle.apps.franceconnect_data.models import Resource
from tests.test_rsa13 import mock_response

CURRENT_YEAR = now().year


USER_INFO_MOCKED_RESPONSES = [
    ['/api/v1/token', {'access_token': 'at-1234', 'id_token': '.e30=.'}],
    [
        '/api/v1/userinfo',
        {
            'sub': 'sub-1234',
            'given_name': 'John',
            'family_name': 'Doe',
            'birthdate': '2001-04-28',
            'birthplace': '13055',
            'birthcountry': '99100',
            'gender': 'male',
        },
    ],
]


DGFIP_MOCKED_RESPONSES = USER_INFO_MOCKED_RESPONSES + [
    [
        '/token',
        {
            'access_token': 'eyJ4NXQiOi',
            'expires_in': 3600,
            'scope': 'RessourceIRDerniere2',
            'token_type': 'Bearer',
        },
    ]
]

DGFIP_MOCKED_RESPONSES += [
    [
        '/impotparticulier/1.0/situations/ir/assiettes/annrev/%s' % year,
        {'rfr': year * 2, 'revenuBrutGlobal': year * 10},
    ]
    for year in range(CURRENT_YEAR - 3, CURRENT_YEAR)
]


@pytest.fixture
def fc(db):
    return tests.utils.make_resource(
        Resource,
        slug='test',
        fc_platform_slug='prod',
        fc_client_id='1234',
        fc_client_secret='abcd',
        fc_scopes='identite_pivot',
    )


def test_init_request(app, fc):
    resp = app.get('/franceconnect-data/test/init_request?origin=http://testserver')
    parsed_location = urlparse(resp.location)
    qs = parse_qs(parsed_location.query)
    assert (
        urlunparse(parsed_location._replace(query='')) == 'https://app.franceconnect.gouv.fr/api/v1/authorize'
    )
    assert dict(qs, nonce=None, state=None) == {
        'acr_values': ['eidas1'],
        'client_id': ['1234'],
        'nonce': None,
        'redirect_uri': ['http://testserver/franceconnect-data/test/callback?origin=http%3A%2F%2Ftestserver'],
        'response_type': ['code'],
        'scope': ['openid identite_pivot'],
        'state': None,
    }


@mock_response(*USER_INFO_MOCKED_RESPONSES)
def test_callback(app, fc):
    resp = app.get(
        'http://testserver/franceconnect-data/test/callback?origin=http%3A%2F%2Ftestserver&code=5678&raise=1'
    )
    data = json.loads(resp.pyquery('#data').text())
    assert data
    assert 'id' in data
    assert data['text'] == 'John Doe né le April 28, 2001'

    resp = app.get('/franceconnect-data/test/data_source?id=' + data['id'])
    assert resp.json['err'] == 0
    assert dict(resp.json['data'][0], id=None) == {
        'franceconnect': {
            'birthdate': '2001-04-28',
            'family_name': 'Doe',
            'gender': 'male',
            'birthplace': '13055',
            'birthcountry': '99100',
            'given_name': 'John',
            'sub': 'sub-1234',
            'hash': '50a8c11bcafc175d2571029b29ace5f3bcb3e06643ff4ac8b291772f788e4153',
        },
        'id': None,
        'text': 'John Doe né le April 28, 2001',
    }

    app.get('/franceconnect-data/test/data_source?id=bad')  # no error


@mock_response(
    ['/api/v1/token', ''],
    [
        '/api/v1/userinfo',
        {
            'sub': 'sub-1234',
            'given_name': 'John',
            'family_name': 'Doe',
            'birthplace': '13055',
            'birthcountry': '99100',
            'birthdate': '2001-04-28',
            'gender': 'male',
        },
    ],
)
def test_callback_error(app, fc):
    resp = app.get(
        'http://testserver/franceconnect-data/test/callback?origin=http%3A%2F%2Ftestserver&code=5678&raise=1'
    )
    assert not resp.pyquery('#data').text()
    error = json.loads(resp.pyquery('#error').text())
    assert error
    assert 'Error in token endpoint response' in resp


@mock_response(*DGFIP_MOCKED_RESPONSES)
def test_dgfip_mode(app, fc):
    resp = app.get(
        'http://testserver/franceconnect-data/test/callback?origin=http%3A%2F%2Ftestserver&code=5678&raise=1&mode=dgfip'
    )
    data = json.loads(resp.pyquery('#data').text())
    assert data
    assert 'id' in data
    assert data['text'] == 'John Doe né le April 28, 2001'

    resp = app.get('/franceconnect-data/test/data_source?mode=dgfip&id=' + data['id'])
    data = resp.json['data'][0]
    assert data['dgfip_ir']
    for year in range(CURRENT_YEAR - 3, CURRENT_YEAR):
        assert data['dgfip_ir'][str(year)]
    assert 'last_known' in data['dgfip_ir']
    last_known_ir = data['dgfip_ir']['last_known']
    past_year = CURRENT_YEAR - 1
    assert last_known_ir['year'] == str(past_year)
    assert last_known_ir['revenuBrutGlobal'] == past_year * 10
    assert last_known_ir['rfr'] == past_year * 2
