import json
from unittest import mock

import pytest
from django.urls import reverse

import tests.utils
from passerelle.apps.arpege_ecp.models import ArpegeECP
from passerelle.utils.jsonresponse import APIError

FAKE_HELLO_RESPONSE = """{"IsSuccess":true,"CodErreur":null,"LibErreur":null,
"Data":"InteropAPI v1 (c) Arpège 2017"}"""

FAKE_LOGIN_OIDC_RESPONSE = """{
  "IsSuccess": true,
  "CodErreur": null,
  "LibErreur": null,
  "Data": {
    "AccessToken": "0f86353f2d87b8b78aaaacc2ecc763e287ded44f773289a5e336546a251718b3",
    "RefreshToken": "a547bf4033ee1f00a0b06fc5c60a57700c95193aaf221a4b15e59cef606b748c"
  }
}"""

FAKE_USER_DEMANDS_RESPONSE = """{
  "IsSuccess": true,
  "CodErreur": null,
  "LibErreur": null,
  "Data": {
    "Pagination": {
      "totalCount": 2,
      "totalPages": 1,
      "prevPageLink": "https://www.espace-citoyens.net/integration01/interop.api/v1/DemandesUsager?scope=data_administratives",
      "nextPageLink": "https://www.espace-citoyens.net/integration01/interop.api/v1/DemandesUsager?scope=data_administratives"
    },
    "results": [
      {
        "url": "https://www.espace-citoyens.net/integration01/espace-citoyens/Demande/SuiviDemande/WI",
        "data_administratives": {
          "CodeQualificationMetier": "TSTINTEGR",
          "CodeQualificationTypeDemande": "TST_A",
          "LibelleQualificationMetier": null,
          "LibelleQualificationTypeDemande": "Test A",
          "titre": "Demand A",
          "libelleFinTraitement": "",
          "date_depot": "2018-05-11",
          "heure_depot": "09:50:46",
          "date_fin_instruction": null,
          "code_etat": "DEPOSEE",
          "libelle_etat": "Deposee"
        },
        "data_demandeur": null,
        "data_formulaire": null,
        "pieces_jointes": null,
        "data_etapes": null
      }
    ]
  }
}"""


@pytest.fixture
def connector(db):
    resource = ArpegeECP.objects.create(
        slug='test', webservice_base_url='http://arpege.net', hawk_auth_id='id', hawk_auth_key='secret'
    )
    return tests.utils.setup_access_rights(resource)


@mock.patch('passerelle.utils.Request.get')
def test_check_status(mocked_get, connector):
    mocked_get.return_value = tests.utils.FakedResponse(content=FAKE_HELLO_RESPONSE, status_code=200)
    resp = connector.check_status()
    assert resp['data'] == 'InteropAPI v1 (c) Arpège 2017'


@mock.patch('passerelle.utils.Request.get')
def test_check_status_error(mocked_get, connector):
    hello_response = json.loads(FAKE_HELLO_RESPONSE)
    del hello_response['Data']
    mocked_get.return_value = tests.utils.FakedResponse(content=json.dumps(hello_response), status_code=200)
    with pytest.raises(Exception) as error:
        connector.check_status()
    assert str(error.value) == 'Invalid credentials'


def test_get_access_token(connector):
    with tests.utils.mock_url(response=FAKE_LOGIN_OIDC_RESPONSE):
        token = connector.get_access_token('nameid')
    assert token == '0f86353f2d87b8b78aaaacc2ecc763e287ded44f773289a5e336546a251718b3'

    with tests.utils.mock_url(response=FAKE_LOGIN_OIDC_RESPONSE, status_code=404):
        with pytest.raises(APIError) as error:
            token = connector.get_access_token('nameid')

    assert ' 404 ' in str(error.value)

    with tests.utils.mock_url(response="content", status_code=200):
        with pytest.raises(APIError) as error:
            token = connector.get_access_token('nameid')
    assert 'no JSON content' in str(error.value)

    with tests.utils.mock_url(response="content", status_code=200):
        with pytest.raises(APIError) as error:
            token = connector.get_access_token('nameid')
    assert 'no JSON content' in str(error.value)

    with tests.utils.mock_url(
        response='{"IsSuccess": false, "CodErreur": "Fail", "LibErreur": "Auth FAIL"}', status_code=200
    ):
        with pytest.raises(APIError) as error:
            token = connector.get_access_token('nameid')
    assert str(error.value) == 'Auth FAIL (Fail)'


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_get_user_forms(mocked_post, mocked_get, app, connector):
    endpoint = reverse(
        'generic-endpoint',
        kwargs={
            'connector': 'arpege-ecp',
            'slug': connector.slug,
            'endpoint': 'api',
            'rest': 'users/nameid/forms',
        },
    )
    assert endpoint == '/arpege-ecp/test/api/users/nameid/forms'

    mocked_post.return_value = tests.utils.FakedResponse(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=200)
    mocked_get.return_value = tests.utils.FakedResponse(content=FAKE_USER_DEMANDS_RESPONSE, status_code=200)
    resp = app.get(endpoint)
    assert resp.json['data']
    for item in resp.json['data']:
        assert item['status'] == 'Deposee'
        assert item['title'] == 'Test A'
        assert item['name'] == 'Test A'
        assert (
            item['url']
            == 'https://www.espace-citoyens.net/integration01/espace-citoyens/Demande/SuiviDemande/WI'
        )
        assert item['form_receipt_datetime'] == '2018-05-11T09:50:46'
        assert item['form_receipt_time'] == '09:50:46'
        assert item['readable'] is True
        assert item['form_status_is_endpoint'] is False


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_get_user_forms_failure(mocked_post, mocked_get, app, connector):
    endpoint = reverse(
        'generic-endpoint',
        kwargs={
            'connector': 'arpege-ecp',
            'slug': connector.slug,
            'endpoint': 'api',
            'rest': 'users/nameid/forms',
        },
    )

    mocked_post.return_value = tests.utils.FakedResponse(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=200)
    mocked_get.return_value = tests.utils.FakedResponse(
        content='{"IsSuccess": false, "CodErreur": "Fail", "LibErreur": "Failed to get demands"}',
        status_code=200,
    )
    resp = app.get(endpoint)
    result = resp.json
    assert result['err'] == 1
    assert result['err_desc'] == 'Failed to get demands (Fail)'


def test_get_user_forms_failure_404(app, connector):
    endpoint = reverse(
        'generic-endpoint',
        kwargs={
            'connector': 'arpege-ecp',
            'slug': connector.slug,
            'endpoint': 'api',
            'rest': 'users/nameid/forms',
        },
    )

    with tests.utils.mock_url(url='/LoginParSubOIDC', response=FAKE_LOGIN_OIDC_RESPONSE):
        with tests.utils.mock_url(url='/DemandesUsager', status_code=404):
            resp = app.get(endpoint)
            result = resp.json
            assert result['err'] == 1
            assert 'Arpege server is down' in result['err_desc']
            assert ' 404 ' in result['err_desc']


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_get_user_forms_failure_no_json(mocked_post, mocked_get, app, connector):
    endpoint = reverse(
        'generic-endpoint',
        kwargs={
            'connector': 'arpege-ecp',
            'slug': connector.slug,
            'endpoint': 'api',
            'rest': 'users/nameid/forms',
        },
    )

    mocked_post.return_value = tests.utils.FakedResponse(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=200)
    mocked_get.return_value = tests.utils.FakedResponse(content='content', status_code=200)
    resp = app.get(endpoint)
    result = resp.json
    assert result['err'] == 1
    assert result['err_desc'] == "No JSON content returned: 'content'"


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_get_user_forms_failure_arpege_error(mocked_post, mocked_get, app, connector):
    endpoint = reverse(
        'generic-endpoint',
        kwargs={
            'connector': 'arpege-ecp',
            'slug': connector.slug,
            'endpoint': 'api',
            'rest': 'users/nameid/forms',
        },
    )

    demands_response = json.loads(FAKE_USER_DEMANDS_RESPONSE)
    demands_response['Data']['results'][0]['data_administratives']['date_depot'] = None

    mocked_post.return_value = tests.utils.FakedResponse(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=200)
    mocked_get.return_value = tests.utils.FakedResponse(content=json.dumps(demands_response), status_code=200)
    resp = app.get(endpoint)
    result = resp.json
    assert result['err'] == 1
    assert 'Arpege error: ' in result['err_desc']


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_get_user_forms_failure_no_token(mocked_post, mocked_get, app, connector):
    endpoint = reverse(
        'generic-endpoint',
        kwargs={
            'connector': 'arpege-ecp',
            'slug': connector.slug,
            'endpoint': 'api',
            'rest': 'users/nameid/forms',
        },
    )

    token_response = json.loads(FAKE_LOGIN_OIDC_RESPONSE)
    del token_response['Data']['AccessToken']
    mocked_post.return_value = tests.utils.FakedResponse(content=json.dumps(token_response), status_code=200)
    mocked_get.return_value = tests.utils.FakedResponse(content='content', status_code=200)
    resp = app.get(endpoint)
    result = resp.json
    assert result['err'] == 1
    assert result['err_desc'] == 'Error on LoginParSubOIDC: missing Data/AccessToken'


@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_get_user_forms_failure_wrong_token(mocked_post, mocked_get, app, connector):
    endpoint = reverse(
        'generic-endpoint',
        kwargs={
            'connector': 'arpege-ecp',
            'slug': connector.slug,
            'endpoint': 'api',
            'rest': 'users/nameid/forms',
        },
    )

    token_response = json.loads(FAKE_LOGIN_OIDC_RESPONSE)
    token_response['Data']['AccessToken'] = None
    mocked_post.return_value = tests.utils.FakedResponse(content=json.dumps(token_response), status_code=200)
    mocked_get.return_value = tests.utils.FakedResponse(content='content', status_code=200)
    resp = app.get(endpoint)
    result = resp.json
    assert result['err'] == 1
    assert result['err_desc'] == 'Error on LoginParSubOIDC: Data/AccessToken is not string'
