"""
Functional tests for the managing sites.

:copyright: Copyright 2013-2017, Dorian Puła
    <dorian.pula@amber-penguin-software.ca>
:license: AGPL v3+
"""

import http
from unittest import mock

import pytest_bdd as bdd
import requests
from pytest_bdd import parsers

from rookeries.sites import models
from tests import utils


# TODO: Rework site management and testing.
# TODO: Rework modification to only allow changes to layout and children...
# TODO: Add a test if the site does not exist for some reason.
bdd.scenarios('site_access.feature')
bdd.scenarios('site_modification.feature')


@bdd.given(
    parsers.parse('I try to modify the site with a non-json request'),
    target_fixture='api_response')
def invalid_non_json_modify_site_response(
        api_response, auth_token_headers, api_base_uri):
    return requests.put(
        url=f'{api_base_uri}/api/site',
        data='',
        headers=auth_token_headers,
    )


@bdd.given(
    parsers.parse('I try to modify the site with an empty request'),
    target_fixture='api_response')
def invalid_empty_modify_site_response(
        api_response, auth_token_headers, api_base_uri):
    return requests.put(
        url=f'{api_base_uri}/api/site',
        json={},
        headers=auth_token_headers,
    )


@bdd.given(parsers.parse('I get the site'), target_fixture='api_response')
def get_site_request(test_site, auth_token_headers, api_base_uri):
    response = requests.get(
        url=f'{api_base_uri}/api/site',
        headers=auth_token_headers,
    )
    return utils.ResponseSampleBundle(response, test_site)


@bdd.then(parsers.parse('I get a valid site with a menu and landing page'))
def assert_site_response(api_response):

    actual_response = utils.extract_response(api_response)
    assert actual_response.status_code == http.HTTPStatus.OK

    expected_json = {
        'name': 'Test Site',
        'links': {'self': '/api/site'},
        'config': mock.ANY,
        'landingPage': mock.ANY,
        'menu': mock.ANY,
    }
    assert expected_json == actual_response.json()


@bdd.given(
    parsers.parse('I try to modify the site'), target_fixture='api_response')
def modify_site_response(
        test_site, api_response, auth_token_headers, api_base_uri):
    test_site = api_response.sample
    site_modification_request = test_site.to_api_json()
    site_modification_request['name'] = 'Modified Test Site'

    response = requests.put(
        url=f'{api_base_uri}/api/site',
        json=site_modification_request,
        headers=auth_token_headers,
    )
    return utils.ResponseSampleBundle(response, test_site)


@bdd.then(parsers.parse('my updates are reflected in the site'))
def assert_updated_site_response(test_site, api_response, db):
    actual_response = utils.extract_response(api_response)
    assert actual_response.status_code == http.HTTPStatus.OK

    expected_json = test_site.to_api_json()
    expected_json['name'] = 'Modified Test Site'
    assert expected_json == actual_response.json()
    assert '/api/site' == actual_response.json()['links']['self']

    # TODO: Remember to reset the state of the site to its original here.
    updated_site = models.Site.find_in_db(db, {})
    updated_site.name = test_site.name
    updated_site.config = test_site.config
    updated_site.menu = test_site.menu
    updated_site.landing_page = test_site.landing_page
    db.create_or_update_document(
        updated_site.to_db_json(), updated_site._id, updated_site._rev)
