"""
Configuration, plugins and fixtures for `pytest`.
"""

import base64
import binascii
import io
import uuid

import pytest
from _pytest.fixtures import SubRequest
from vws import VWS, CloudRecoService

from mock_vws.database import VuforiaDatabase
from tests.mock_vws.utils import Endpoint

pytest_plugins = [
    'tests.mock_vws.fixtures.prepared_requests',
    'tests.mock_vws.fixtures.credentials',
    'tests.mock_vws.fixtures.vuforia_backends',
]


@pytest.fixture(name='vws_client')
def fixture_vws_client(vuforia_database: VuforiaDatabase) -> VWS:
    """
    A VWS client for an active VWS database.
    """
    return VWS(
        server_access_key=vuforia_database.server_access_key,
        server_secret_key=vuforia_database.server_secret_key,
    )


@pytest.fixture()
def cloud_reco_client(vuforia_database: VuforiaDatabase) -> CloudRecoService:
    """
    A query client for an active VWS database.
    """
    return CloudRecoService(
        client_access_key=vuforia_database.client_access_key,
        client_secret_key=vuforia_database.client_secret_key,
    )


@pytest.fixture(name='inactive_vws_client')
def fixture_inactive_vws_client(inactive_database: VuforiaDatabase) -> VWS:
    """
    A client for an inactive VWS database.
    """
    return VWS(
        server_access_key=inactive_database.server_access_key,
        server_secret_key=inactive_database.server_secret_key,
    )


@pytest.fixture()
def target_id(
    image_file_success_state_low_rating: io.BytesIO,
    vws_client: VWS,
) -> str:
    """
    Return the target ID of a target in the database.

    The target is one which will have a 'success' status when processed.
    """
    return vws_client.add_target(
        name=uuid.uuid4().hex,
        width=1,
        image=image_file_success_state_low_rating,
        active_flag=True,
        application_metadata=None,
    )


@pytest.fixture(
    params=[
        '_add_target',
        '_database_summary',
        '_delete_target',
        '_get_duplicates',
        '_get_target',
        '_target_list',
        '_target_summary',
        '_update_target',
        '_query',
    ],
)
def endpoint(request: SubRequest) -> Endpoint:
    """
    Return details of an endpoint for the Target API or the Query API.
    """
    endpoint_fixture: Endpoint = request.getfixturevalue(request.param)
    return endpoint_fixture


@pytest.fixture(
    params=[
        pytest.param(
            'abcde',
            id='Length is one more than a multiple of four.',
        ),
        pytest.param(
            # We choose XN because it is different when decoded then encoded:
            #
            #   print(base64.b64encode(base64.b64decode('XN==')))
            #
            # prints ``XA==``.
            'XN',
            id='Length is two more than a multiple of four.',
        ),
        pytest.param(
            'XNA',
            id='Length is three more than a multiple of four.',
        ),
    ],
)
def not_base64_encoded_processable(request: SubRequest) -> str:
    """
    Return a string which is not decodable as base64 data, but Vuforia will
    respond as if this is valid base64 data.
    ``UNPROCESSABLE_ENTITY`` when this is given.
    """
    not_base64_encoded_string: str = request.param

    with pytest.raises(binascii.Error):
        base64.b64decode(not_base64_encoded_string, validate=True)

    return not_base64_encoded_string


@pytest.fixture(
    params=[
        pytest.param(
            'aaa"',
            id='Includes a character which is not a base64 digit.',
        ),
        pytest.param('"', id='Not a base64 character.'),
    ],
)
def not_base64_encoded_not_processable(request: SubRequest) -> str:
    """
    Return a string which is not decodable as base64 data, and Vuforia will
    return an ``UNPROCESSABLE_ENTITY`` response when this is given.
    """
    not_base64_encoded_string: str = request.param

    with pytest.raises(binascii.Error):
        base64.b64decode(not_base64_encoded_string, validate=True)

    return not_base64_encoded_string
