"""
This test suite contains tests to validate certificate create/edit/delete with
different possible way and with different roles of users.
Test requirement:
Below Env variables need to be 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_VALID_TLS_KEY - takes authentic certificate key base64 encoded
RANCHER_VALID_TLS_CERT - takes authentic certificate base64 encoded
RANCHER_BYO_TLS_KEY - takes self signed certificate key base64 encoded
RANCHER_BYO_TLS_CERT - takes self signed certificate base64 encoded
AWS_HOSTED_ZONE_ID - Zone Id in AWS route53 where route53 will be created.
RANCHER_TEST_RBAC - To enable rbac tests
"""

from .common import (ApiError, CLUSTER_MEMBER, CLUSTER_OWNER, create_kubeconfig,
                     create_ns, create_project_and_ns,
                     get_cluster_client_for_token, get_project_client_for_token,
                     get_user_client, get_user_client_and_cluster, if_test_rbac,
                     PROJECT_OWNER, PROJECT_MEMBER, PROJECT_READ_ONLY,
                     random_test_name, rbac_get_namespace, rbac_get_project,
                     rbac_get_user_token_by_role, TEST_IMAGE, USER_TOKEN,
                     validate_ingress_using_endpoint, validate_workload,
                     wait_for_ingress_to_active, base64)
from lib.aws import AmazonWebServices
from pathlib import Path
import pytest
import os
import time


namespace = {"p_client": None, "ns": None, "cluster": None, "project": None,
             "c_client": None, "cert_valid": None, "cert_ssc": None,
             "cert_allns_valid": None, "cert_allns_ssc": None, "node_id": None}

route_entry_53_1 = random_test_name('auto-valid') + '.qa.rancher.space'
route_entry_53_2 = random_test_name('auto-ssc') + '.qa.rancher.space'


def get_ssh_key(ssh_key_name):
    home = str(Path.home())
    path = '{}/.ssh/{}'.format(home, ssh_key_name)
    if os.path.exists(path):
        with open(path, 'r') as f:
            ssh_key = f.read()
        return ssh_key


def get_private_key(env_var, key_name):
    key = os.environ.get(env_var)
    if key is not None:
        return base64.b64decode(key).decode("utf-8")
    else:
        return get_ssh_key(key_name)


rancher_private_key = get_private_key('RANCHER_VALID_TLS_KEY',
                                      'privkey.pem')
rancher_cert = get_private_key('RANCHER_VALID_TLS_CERT', 'fullchain.pem')
rancher_ssc_private_key = get_private_key('RANCHER_BYO_TLS_KEY',
                                          'key.pem')
rancher_ssc_cert = get_private_key('RANCHER_BYO_TLS_CERT', 'cert.pem')

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


@pytest.mark.usefixtures("create_project_client")
class TestCertificate:

    @pytest.fixture(autouse="True")
    def certificate_test_setup(self):
        """
        Test set up which runs before and after all the tests in the class
        Creates Workload_2 if required and delete all the workload and ingres
        created after test execution.
        """
        self.p_client = namespace["p_client"]
        self.ns = namespace["ns"]
        self.c_client = namespace["c_client"]
        self.cluster = namespace["cluster"]
        self.project = namespace["project"]
        self.certificate_valid = namespace["cert_valid"]
        self.certificate_ssc = namespace["cert_ssc"]
        self.certificate_all_ns_valid = namespace["cert_allns_valid"]
        self.certificate_all_ns_ssc = namespace["cert_allns_ssc"]
        self.node_id = namespace["node_id"]
        wl_name = random_test_name("workload-test")
        wl_con = [{"name": "wk1-test",
                   "image": TEST_IMAGE}]
        scheduling = {"node": {"nodeId": self.node_id}}
        self.workload = self.p_client.create_workload(
            name=wl_name, containers=wl_con, namespaceId=self.ns.id,
            scheduling=scheduling
        )
        self.ingress = None
        self.workload_2 = None
        yield
        self.p_client.delete(self.workload)
        if self.workload_2 is not None:
            self.p_client.delete(self.workload_2)
        if self.ingress is not None:
            self.p_client.delete(self.ingress)

    def test_certificate_create_validcert_for_single_ns(self):
        """
        Test steps:
        1. Validate the workload available in ns-certificate namespace
        2. Create an ingress including trusted certificate scoped for current
        namespace and route53 host.
        3. validate the ingress using endpoint
        """
        ingress_name = random_test_name("ingress-test")
        host = route_entry_53_1
        path = "/name.html"
        rule = {"host": host,
                "paths": [{"path": path, "workloadIds": [self.workload.id],
                           "targetPort": "80"}]}
        tls = {"certificateId": self.certificate_valid.id, "hosts": [host]}
        validate_workload(self.p_client, self.workload, "deployment",
                          self.ns.name)
        self.ingress = self.p_client.create_ingress(
            name=ingress_name, namespaceId=self.ns.id, rules=[rule], tls=[tls]
        )
        wait_for_ingress_to_active(self.p_client, self.ingress)
        validate_ingress_using_endpoint(
            self.p_client, self.ingress, [self.workload], certcheck=True)

    def test_certificate_create_validcert_for_all_ns(self):
        """
        Test steps:
        1. Validate the workload available in ns-certificate namespace
        2. Create an ingress including trusted certificate scoped for all
        namespace and route53 host.
        3. validate the ingress using endpoint
        """
        ingress_name = random_test_name("ingress-test")
        host = route_entry_53_1
        path = "/name.html"
        rule = {"host": host,
                "paths": [{"path": path, "workloadIds": [self.workload.id],
                           "targetPort": "80"}]
                }
        tls = {"certificateId": self.certificate_all_ns_valid.id,
               "hosts": [host]
               }
        validate_workload(self.p_client, self.workload, "deployment",
                          self.ns.name)
        self.ingress = self.p_client.create_ingress(
            name=ingress_name, namespaceId=self.ns.id, rules=[rule], tls=[tls]
        )
        wait_for_ingress_to_active(self.p_client, self.ingress)
        validate_ingress_using_endpoint(
            self.p_client, self.ingress, [self.workload], certcheck=True)

    def test_certificate_create_validcert_for_all_ns_2(self):
        """
        Test steps:
        1. Create a namespace
        2. Create a workload in namespace created above.
        3. Validate the workload.
        4. Create an ingress including trusted certificate scoped for all
        namespace and route53 host.
        5. validate the ingress using endpoint
        """
        wl_name = random_test_name("workload-test")
        wl_con = [{"name": "wk2-test",
                   "image": TEST_IMAGE}]
        scheduling = {"node": {"nodeId": self.node_id}}
        ns_2 = create_ns(self.c_client, self.cluster, self.project)
        self.workload_2 = self.p_client.create_workload(
            name=wl_name, containers=wl_con, namespaceId=ns_2.id,
            scheduling=scheduling
            )
        validate_workload(self.p_client, self.workload_2, "deployment",
                          ns_2.name)
        ingress_name = random_test_name("ingress-test")
        host = route_entry_53_1
        path = "/name.html"
        rule = {"host": host,
                "paths": [{"path": path, "workloadIds": [self.workload_2.id],
                           "targetPort": "80"}]
                }
        tls = {"certificateId": self.certificate_all_ns_valid.id,
               "hosts": [host]
               }
        self.ingress = self.p_client.create_ingress(
            name="{}-2".format(ingress_name), namespaceId=ns_2.id,
            rules=[rule], tls=[tls]
        )
        wait_for_ingress_to_active(self.p_client, self.ingress)
        validate_ingress_using_endpoint(