"""
This file contains test related to add registry and
deploying workloads with those registry.
Test requirement:
Below Env variables need to set
CATTLE_TEST_URL - url to rancher server
ADMIN_TOKEN - Admin token from rancher
USER_TOKEN - User token from rancher
RANCHER_CLUSTER_NAME - Cluster name to run test on
RANCHER_REGISTRY - quay.io, dockerhub, custom etc
RANCHER_TEST_CLIENT_IMAGE - Path to image eg. quay.io/myimage/ubuntuimage
RANCHER_TEST_RBAC - Boolean (Optional), To run rbac tests
"""

from .common import *  # NOQA

CLUSTER_NAME = os.environ.get("CLUSTER_NAME", "")
namespace = {"p_client": None, "ns": None, "cluster": None, "project": None}
REGISTRY_USER_NAME = os.environ.get('RANCHER_REGISTRY_USER_NAME', "None")
REGISTRY_PASSWORD = os.environ.get('RANCHER_REGISTRY_PASSWORD', "None")
TEST_CLIENT_IMAGE = os.environ.get('RANCHER_TEST_CLIENT_IMAGE', "None")
REGISTRY = os.environ.get('RANCHER_REGISTRY', "None")

rbac_role_list = [
                  CLUSTER_OWNER,
                  CLUSTER_MEMBER,
                  PROJECT_OWNER,
                  PROJECT_MEMBER,
                  PROJECT_READ_ONLY
                 ]


def test_create_registry_single_namespace():
    """
    This test creates a namespace and creates a registry.
    Validates the workload created in same namespace using registry image
    comes up active.
    """
    p_client = namespace["p_client"]
    ns = namespace["ns"]
    registry = create_registry_validate_workload(p_client, ns)
    delete_registry(p_client, registry)


def test_create_registry_all_namespace():
    p_client = namespace["p_client"]
    c_client = namespace["c_client"]
    cluster = namespace["cluster"]
    project = namespace["project"]

    ns = namespace["ns"]
    registry = create_registry_validate_workload(p_client, ns, allns=True)

    # Create and validate workload in a new namespace
    new_ns = create_ns(c_client, cluster, project)
    create_validate_workload(p_client, new_ns)
    delete_registry(p_client, registry)


def test_delete_registry_all_namespace():
    p_client = namespace["p_client"]
    c_client = namespace["c_client"]
    cluster = namespace["cluster"]
    project = namespace["project"]
    ns = namespace["ns"]
    new_ns = create_ns(c_client, cluster, project)

    registry = create_registry_validate_workload(p_client, ns, allns=True)
    delete_registry(p_client, registry)

    print("Verify workloads cannot be created in all the namespaces")
    create_validate_workload_with_invalid_registry(p_client, ns)
    create_validate_workload_with_invalid_registry(p_client, new_ns)


def test_delete_registry_single_namespace():
    p_client = namespace["p_client"]
    ns = namespace["ns"]

    registry = create_registry_validate_workload(p_client, ns)
    delete_registry(p_client, registry)

    print("Verify workload cannot be created in the namespace after registry")
    "deletion"
    create_validate_workload_with_invalid_registry(p_client, ns)


def test_edit_registry_single_namespace():
    p_client = namespace["p_client"]
    ns = namespace["ns"]

    name = random_test_name("registry")
    # Create registry with invalid username and password
    registries = {REGISTRY: {"username": "testabc",
                             "password": "abcdef"}}

    registry = p_client.create_namespacedDockerCredential(
        registries=registries, name=name,
        namespaceId=ns.id)

    create_validate_workload_with_invalid_registry(p_client, ns)

    # Update registry with valid username and password
    new_registries = {REGISTRY: {"username": REGISTRY_USER_NAME,
                                 "password": REGISTRY_PASSWORD}}
    p_client.update(registry, name=registry.name,
                    namespaceId=ns['name'],
                    registries=new_registries)

    # Validate workload after registry update
    create_validate_workload(p_client, ns)
    delete_registry(p_client, registry)


def test_edit_registry_all_namespace():
    p_client = namespace["p_client"]
    c_client = namespace["c_client"]
    cluster = namespace["cluster"]
    project = namespace["project"]
    ns = namespace["ns"]

    name = random_test_name("registry")

    # Create registry with invalid username and password
    registries = {REGISTRY: {"username": "testabc",
                             "password": "abcdef"}}

    registry = p_client.create_dockerCredential(
        registries=registries, name=name)

    create_validate_workload_with_invalid_registry(p_client, ns)

    # Update registry with correct username and password
    new_registries = {REGISTRY: {"username": REGISTRY_USER_NAME,
                                 "password": REGISTRY_PASSWORD}}

    p_client.update(registry, name=registry.name,
                    registries=new_registries)

    new_ns = create_ns(c_client, cluster, project)

    # Validate workload in all namespaces after registry update
    create_validate_workload(p_client, ns)
    create_validate_workload(p_client, new_ns)
    delete_registry(p_client, registry)


def test_registry_cross_namespace_access():
    """
    This test creates two namespace and creates registry for first namespace.
    It creates two workload in each namespace.
    Validates workload created in first namespace comes up healthy but workload
    in 2nd workspace doesn't become healthy.
    """
    p_client = namespace["p_client"]
    c_client = namespace["c_client"]
    cluster = namespace["cluster"]
    project = namespace["project"]
    ns_1 = namespace["ns"]
    ns_2 = create_ns(c_client, cluster, project)
    registry = create_registry_validate_workload(p_client, ns_1)
    create_validate_workload_with_invalid_registry(p_client, ns_2)
    delete_registry(p_client, registry)


@if_test_rbac
@pytest.mark.parametrize("role", rbac_role_list)
def test_rbac_registry_create_single_namespace(role):
    """
    Creates registry with given role to a single namespace
    Runs only if RANCHER_TEST_RBAC is True in env. variable
    @param role: User role in rancher eg. project owner, project member etc
    """
    token = rbac_get_user_token_by_role(role)
    project = rbac_get_project()
    ns = rbac_get_namespace()
    p_client = get_project_client_for_token(project, token)
    if role in (CLUSTER_MEMBER, PROJECT_READ_ONLY):
        with pytest.raises(ApiError) as e:
            registry = create_registry_validate_workload(p_client, ns)
        assert e.value.error.status == 403
        assert e.value.error.code == 'PermissionDenied'
    else:
        registry = create_registry_validate_workload(p_client, ns)
        delete_registry(p_client, registry)


@if_test_rbac
@pytest.mark.parametrize("role", rbac_role_list)
def test_rbac_registry_create_all_namespace(role):
    """
    Runs only if RANCHER_TEST_RBAC is True in env. variable.
    Creates registry scoped all namespace and for
    multiple role passed in parameter.
    @param role: User role in rancher eg. project owner, project member etc
    """
    c_client = namespace["c_client"]
    cluster = namespace["cluster"]
    token = rbac_get_user_token_by_role(role)
    project = rbac_get_project()
    ns = rbac_get_namespace()
    p_client = get_project_client_for_token(project, token)
    if role in (CLUSTER_MEMBER, PROJECT_READ_ONLY):
        with pytest.raises(ApiError) as e:
            registry = \
                create_registry_validate_workload(p_client, ns, allns=True)
        assert e.value.error.status == 403
        assert e.value.error.code == 'PermissionDenied'
    else:
        registry = create_registry_validate_workload(p_client, ns, allns=True)

        # Create and validate workload in a new namespace
        new_ns = create_ns(c_client, cluster, project)
        create_validate_workload(p_client, new_ns)
        delete_registry(p_client, registry)


@if_test_rbac
@pytest.mark.parametrize("role", rbac_role_list)
def test_rbac_registry_delete_single_namespace(role):
    """
    Runs only if RANCHER_TEST_RBAC is True in env. variable.
    Creates a registry for single namespace, deploys a workload
    and delete registry afterwards.
    Validates the workload which has become invalid on registry deletion.
    @param role: User role in rancher eg. project owner, project member etc
    """
    c_owner_token = rbac_get_user_token_by_role(rbac_role_list[0])
    project = rbac_get_project()
    p_client_for_c_owner = get_project_client_for_token(project, c_owner_token)
    token = rbac_get_user_token_by_role(role)
    ns = rbac_get_namespace()
    p_client = get_project_client_for_token(project, token)

    registry = create_registry_validate_workload(p_client_for_c_owner, ns)

    if role in (CLUSTER_MEMBER, PROJECT_READ_ONLY):
        with pytest.raises(ApiError) as e:
            delete_registry(p_client, registry)
        assert e.value.error.status == 403
        assert e.value.error.code == 'Forbidden'
        delete_registry(p_client_for_c_owner, registry)
    else:
        delete_registry(p_client, registry)

        print("Verify workload cannot be created in the namespace after "
              "registry deletion")
        create_validate_workload_with_invalid_registry(p_client, ns)


@if_test_rbac
@pytest.mark.parametrize("role", rbac_role_list)
def test_rbac_registry_delete_all_namespace(role):
    """
    Runs only if RANCHER_TEST_RBAC is True in env. variable.
    Creates a registry scoped for all namespace, deploys a workload
    and delete registry afterwards.
    Validates the workload which has become invalid on registry deletion.
    @param role: User role in rancher eg. project owner, project member etc
    """
    c_client = namespace["c_client"]
    cluster = namespace["cluster"]
    c_owner_token = rbac_get_user_token_by_role(rbac_role_list[0])
    project = rbac_get_project()
    p_client_for_c_owner = get_project_client_for_token(project, c_owner_token)
    token = rbac_get_user_token_by_role(role)
    p_client = get_project_client_for_token(project, token)
    ns = rbac_get_namespace()
    new_ns = create_ns(c_client, cluster, project)
    registry = \
        create_registry_validate_workload(p_client_for_c_owner, ns)
    if role in (CLUSTER_MEMBER, PROJECT_READ_ONLY):
        with pytest.raises(ApiError) as e:
            delete_registry(p_client, registry)
        assert e.value.error.status == 403
        assert e.value.error.code == 'Forbidden'
        delete_registry(p_client_for_c_owner, registry)
    else:
        delete_registry(p_client, registry)

        print("Verify workloads cannot be created in all the namespaces")
        create_validate_workload_with_invalid_registry(p_client, ns)
        create_validate_workload_with_invalid_registry(p_client, new_ns)


@if_test_rbac
@pytest.mark.parametrize("role", rbac_role_list)
def test_rbac_registry_edit_single_namespace(role):
    """
    Runs only if RANCHER_TEST_RBAC is True in env. variable.
    Creates registry with invalid credential for single namespace,
    deploys workload with invalid registry and validate the workload
    is not up.
    Update the registry with correct credential and validates workload.
    @param role: User role in rancher eg. project owner, project member etc
    """
    c_owner_token = rbac_get_user_token_by_role(rbac_role_list[0])
    project = rbac_get_project()
    p_client_for_c_owner = get_project_client_for_token(project, c_owner_token)
    token = rbac_get_user_token_by_role(role)
    ns = rbac_get_namespace()
    p_client = get_project_client_for_token(project, token)

    name = random_test_name("registry")
    # registry with invalid username and password
    registries = {REGISTRY: {"username": "testabc",
                             "password": "abcdef"}}
    # registry with valid username and password
    new_registries = {REGISTRY: {"username": REGISTRY_USER_NAME,
                                 "password": REGISTRY_PASSWORD}}
    # Create registry with wrong credentials
    registry = p_client_for_c_owner.create_namespacedDockerCredential(
        registries=registries, name=name, namespaceId=ns.id)

    if role in (CLUSTER_MEMBER, PROJECT_READ_ONLY):
        with pytest.raises(ApiError) as e:
            p_client.update(registry, name=registry.name,
                            namespaceId=ns['name'],
                            registries=new_registries)
        assert e.value.error.status == 404
        assert e.value.error.code == 'NotFound'
        delete_registry(p_client_for_c_owner, registry)
    else:
        create_validate_workload_with_invalid_registry(p_client, ns)
        # Update registry with valid username and password
        p_client.update(registry, name=registry.name,
                        namespaceId=ns['name'],
                        registries=new_registries)

        # Validate workload after registry update
        create_validate_workload(p_client, ns)
        delete_registry(p_client, registry)


@if_test_rbac
@pytest.mark.parametrize("role", rbac_role_list)
def test_rbac_registry_edit_all_namespace(role):
    """
    Runs only if RANCHER_TEST_RBAC is True in env. variable.
    Creates registry with invalid credential scoped for all namespace,
    deploys workload with invalid registry and validate the workload
    is not up.
    Update the registry with correct credential and validates workload.
    @param role: User role in rancher eg. project owner, project member etc
    @param role:
    """
    c_client = namespace["c_client"]
    cluster = namespace["cluster"]
    c_owner_token = rbac_get_user_token_by_role(rbac_role_list[0])
    project = rbac_get_project()
    p_client_for_c_owner = get_project_client_for_token(project, c_owner_token)
    token = rbac_get_user_token_by_role(role)
    project = rbac_get_project()
    p_client = get_project_client_for_token(project, token)
    ns = rbac_get_namespace()

    name = random_test_name("registry")
    registries = {REGISTRY: {"username": "testabc",
                             "password": "abcdef"}}
    new_registries = {REGISTRY: {"username": REGISTRY_USER_NAME,
                                 "password": REGISTRY_PASSWORD}}
    # Create registry with invalid username and password
    registry = p_client_for_c_owner.create_dockerCredential(
        registries=registries, name=name)