"""
Tests that test the view functionality of our capability request REST API.
The logic can be found in `capability/views/capability_request.py`.
"""

import http
import pytest

from capability.views.capability_request import (
    create_capability_request,
    delete_capability_request,
    submit_capability_request,
    view_active_capability_requests,
    view_capability_request,
    view_created_capability_requests,
)
from pyramid.httpexceptions import HTTPBadRequest, HTTPNotFound, HTTPPreconditionFailed
from pyramid.testing import DummyRequest

from workspaces.capability.enums import CapabilityRequestState

# pylint: disable=E0401


def test_view_capability_request(request_null_capability: DummyRequest):
    """
    Tests the view_capability_request view to make sure it properly returns the info of a capability request

    :param request_null_capability: Dummy Pyramid request object set up with mocked DB access
    supporting the null capability
    """

    expected_response = {
        "type": "CapabilityRequest",
        "capability_name": "null",
        "id": 0,
        "state": "Created",
    }
    request_null_capability.matchdict["capability_name"] = "null"
    request_null_capability.matchdict["request_id"] = 0
    response = view_capability_request(request_null_capability)
    assert response.status_code == http.HTTPStatus.OK
    for entry in expected_response:
        assert entry in response.json_body


def test_view_capability_request_not_found(request_null_capability: DummyRequest):
    """
    Tests the view_capability_request view to make sure it properly returns a 404 Not Found exception
    when a capability request does not exist

    :param request_null_capability: Dummy Pyramid request object set up with mocked DB access
    supporting the null capability
    """

    request_null_capability.matchdict["capability_name"] = "null"
    request_null_capability.matchdict["request_id"] = -1
    response = view_capability_request(request_null_capability)
    assert response.status_code == http.HTTPStatus.NOT_FOUND
    assert isinstance(response, HTTPNotFound)


def test_view_active_capability_requests(request_null_capability: DummyRequest):
    """
    Tests view_active_capability_requests to ensure it properly returns a list of active requests
    """
    expected_response = {
        "active_requests": [
            {
                "type": "CapabilityRequest",
                "id": 0,
                "capability_name": "null",
                "state": "Created",
                "parameters": None,
                "current_execution": None,
            },
            {
                "type": "CapabilityRequest",
                "id": 3,
                "capability_name": "null",
                "state": "Submitted",
                "parameters": '{"arguments": "-g"}',
                "current_execution": None,
            },
        ]
    }
    request_null_capability.matchdict["capability_name"] = "null"
    response = view_active_capability_requests(request_null_capability)
    assert response.status_code == http.HTTPStatus.OK

    for expected_request, request in zip(expected_response["active_requests"], response.json_body["active_requests"]):
        assert expected_request["id"] == request["id"]
        assert expected_request["parameters"] == request["parameters"]


def test_view_active_capability_requests_not_found(request_null_capability: DummyRequest):
    """
    Tests view_active_capability_requests to ensure it returns HTTP Not Found when appropriate
    """
    request_null_capability.matchdict["capability_name"] = "not_found"
    response = view_active_capability_requests(request_null_capability)
    assert response.status_code == http.HTTPStatus.NOT_FOUND


def test_view_created_capability_requests(request_null_capability: DummyRequest):
    """
    Tests view_created_capability_requests to ensure it returns a list of created requests
    """
    expected_response = {
        "active_requests": [
            {
                "type": "CapabilityRequest",
                "id": 0,
                "capability_name": "null",
                "state": "Created",
                "parameters": None,
                "current_execution": None,
            },
        ]
    }
    request_null_capability.matchdict["capability_name"] = "null"
    response = view_created_capability_requests(request_null_capability)
    assert response.status_code == http.HTTPStatus.OK

    for expected_request, request in zip(expected_response["active_requests"], response.json_body["active_requests"]):
        assert expected_request["id"] == request["id"]
        assert expected_request["parameters"] == request["parameters"]


def test_view_created_capability_requests_not_found(request_null_capability: DummyRequest):
    """
    Tests view_created_capability_requests to ensure it returns HTTP Not Found when appropriate
    """
    request_null_capability.matchdict["capability_name"] = "not_found"
    response = view_created_capability_requests(request_null_capability)
    assert response.status_code == http.HTTPStatus.NOT_FOUND


def test_create_capability_request(request_null_capability: DummyRequest):
    """
    Tests the create capability view to make sure it properly supports creation of capabilities

    :param request_null_capability: Dummy Pyramid request object set up with mocked DB access
    supporting the null capability
    """

    request_null_capability.matchdict["capability_name"] = "null"
    request_null_capability.json_body = {"parameters": "-g", "versions": []}

    # Assert test capability not in list of capabilities (mocked)
    assert not request_null_capability.capability_info.lookup_capability_request(4)

    response = create_capability_request(request_null_capability)
    assert response.status_code == http.HTTPStatus.OK
    expected_response = {
        "type": "CapabilityRequest",
        "capability_name": "null",
        "id": 3,
        "state": CapabilityRequestState.Created.name,
    }
    for entry in expected_response:
        assert entry in response.json_body
    # Assert test capability has been added to list of capabilities (mocked)
    assert request_null_capability.capability_info.lookup_capability_request(3)


def test_create_capability_request_error(request_null_capability: DummyRequest):
    """
    Tests that the create_capability_request view correctly responds with exceptions given bad input

    :param request_null_capability: Dummy Pyramid request object set up with mocked DB access
    supporting the null capability
    """
    request_null_capability.matchdict["capability_name"] = "null"
    request_null_capability.json_body = {"bad": "param"}
    response_bad_params = create_capability_request(request_null_capability)
    assert response_bad_params.status_code == http.HTTPStatus.BAD_REQUEST
    assert isinstance(response_bad_params, HTTPBadRequest)

    request_null_capability.matchdict["capability_name"] = "does_not_exist"
    request_null_capability.json_body = {"parameters": "-g", "versions": []}
    response_does_not_exist = create_capability_request(request_null_capability)
    assert response_does_not_exist.status_code == http.HTTPStatus.PRECONDITION_FAILED
    assert isinstance(response_does_not_exist, HTTPPreconditionFailed)


def test_submit_capability_request(request_null_capability: DummyRequest):
    """
    Tests that the submit_capability_request view correctly executes its logic

    :param request_null_capability: Dummy Pyramid request object set up with mocked DB access
    supporting the null capability
    """

    request_null_capability.matchdict["capability_name"] = "null"
    request_null_capability.matchdict["request_id"] = 0
    response = submit_capability_request(request_null_capability)
    assert response.status_code == http.HTTPStatus.OK


def test_submit_capability_request_error(request_null_capability: DummyRequest):
    """
    Tests that the submit_capability_request view correctly executes its logic

    :param request_null_capability: Dummy Pyramid request object set up with mocked DB access
    supporting the null capability
    """

    request_null_capability.matchdict["capability_name"] = "null"
    request_null_capability.matchdict["request_id"] = -1
    response = submit_capability_request(request_null_capability)
    assert response.status_code == http.HTTPStatus.PRECONDITION_FAILED
    assert isinstance(response, HTTPPreconditionFailed)


def test_delete_capability_request(request_null_capability: DummyRequest):
    """
    Tests that the delete_capability_request view correctly executes its logic

    :param request_null_capability: Dummy Pyramid request object set up with mocked DB access
    supporting the null capability
    """

    request_null_capability.capability_info.capability_executions = []
    request_null_capability.matchdict["capability_name"] = "null"
    request_null_capability.matchdict["request_id"] = 0
    response = delete_capability_request(request_null_capability)
    assert response.status_code == http.HTTPStatus.OK


@pytest.mark.skip("Broken due to queue/messenger rework")
def test_delete_capability_request_error(request_null_capability: DummyRequest):
    """
    Tests that the delete_capability_request view correctly executes its logic

    :param request_null_capability: Dummy Pyramid request object set up with mocked DB access
    supporting the null capability
    """

    # Request cannot be deleted
    request_id = request_null_capability.matchdict["request_id"] = 1
    capability_request = request_null_capability.capability_info.lookup_capability_request(request_id)
    request_null_capability.matchdict["capability_name"] = "null"
    request_null_capability.capability_service.run_capability(capability_request)
    response = delete_capability_request(request_null_capability)
    assert response.status_code == http.HTTPStatus.BAD_REQUEST
    assert isinstance(response, HTTPBadRequest)

    # Request does not exist
    request_null_capability.matchdict["request_id"] = -1
    response = delete_capability_request(request_null_capability)
    assert response.status_code == http.HTTPStatus.PRECONDITION_FAILED
    assert isinstance(response, HTTPPreconditionFailed)