from os import path
from time import sleep

from kubernetes.client.rest import ApiException
from nephos.fabric.settings import get_namespace
from nephos.fabric.utils import get_pod
from nephos.helpers.helm import HelmPreserve, helm_install, helm_upgrade
from nephos.helpers.k8s import ingress_read, secret_read
from nephos.helpers.misc import execute_until_success

CURRENT_DIR = path.abspath(path.split(__file__)[0])


# Core sub-functions
def ca_chart(opts, release, upgrade=False, verbose=False):
    values_dir = opts["core"]["dir_values"]
    repository = opts["core"]["chart_repo"]
    ca_namespace = get_namespace(opts, ca=release)
    # PostgreSQL (Upgrades here are dangerous, deactivated by default)
    helm_install(
        "stable",
        "postgresql",
        "{}-pg".format(release),
        ca_namespace,
        config_yaml="{dir}/postgres-ca/{name}-pg.yaml".format(
            dir=values_dir, name=release
        ),
        verbose=verbose,
    )
    psql_secret = secret_read(
        "{}-pg-postgresql".format(release), ca_namespace, verbose=verbose
    )
    # Different key depending of PostgreSQL version
    psql_password = (
        psql_secret.get("postgres-password") or psql_secret["postgresql-password"]
    )
    env_vars = [("externalDatabase.password", psql_password)]
    # Fabric CA
    if not upgrade:
        helm_install(
            repository,
            "hlf-ca",
            release,
            ca_namespace,
            config_yaml="{dir}/hlf-ca/{name}.yaml".format(dir=values_dir, name=release),
            env_vars=env_vars,
            verbose=verbose,
        )
    else:
        # TODO: Remove this try/catch once all CAs are updated
        try:
            preserve = (
                HelmPreserve("{}-hlf-ca".format(release), "CA_ADMIN", "adminUsername"),
                HelmPreserve(
                    "{}-hlf-ca".format(release), "CA_PASSWORD", "adminPassword"
                ),
            )
            helm_upgrade(
                repository,
                "hlf-ca",
                release,
                ca_namespace,
                config_yaml="{dir}/hlf-ca/{name}.yaml".format(
                    dir=values_dir, name=release
                ),
                env_vars=env_vars,
                preserve=preserve,
                verbose=verbose,
            )
        except:
            preserve = (
                HelmPreserve(
                    "{}-hlf-ca--ca".format(release), "CA_ADMIN", "adminUsername"
                ),
                HelmPreserve(
                    "{}-hlf-ca--ca".format(release), "CA_PASSWORD", "adminPassword"
                ),
            )
            helm_upgrade(
                repository,
                "hlf-ca",
                release,
                ca_namespace,
                config_yaml="{dir}/hlf-ca/{name}.yaml".format(
                    dir=values_dir, name=release
                ),
                env_vars=env_vars,
                preserve=preserve,
                verbose=verbose,
            )


def ca_enroll(pod_exec):
    alive = False
    while not alive:
        res = pod_exec.logs()
        if "Listening on" in res:
            alive = True
        else:
            sleep(15)
    # Enroll CA Admin if necessary
    ca_cert, _ = pod_exec.execute(
        "cat /var/hyperledger/fabric-ca/msp/signcerts/cert.pem"
    )
    if not ca_cert:
        enrolled_id = False
        while not enrolled_id:
            res, err = pod_exec.execute(
                "bash -c 'fabric-ca-client enroll -d -u http://$CA_ADMIN:$CA_PASSWORD@$SERVICE_DNS:7054'"
            )
            if not err:
                enrolled_id = True
            else:
                sleep(15)


def check_ca(ingress_host, verbose=False):
    # Check that CA ingress is operational
    command = "curl https://{ingress}/cainfo".format(ingress=ingress_host)
    execute_until_success(command, verbose=verbose)


# Runner
def setup_ca(opts, upgrade=False, verbose=False):
    for ca_name, ca_values in opts["cas"].items():
        ca_namespace = get_namespace(opts, ca=ca_name)
        # Install Charts
        ca_chart(opts=opts, release=ca_name, upgrade=upgrade, verbose=verbose)

        # Obtain CA pod and Enroll
        pod_exec = get_pod(
            namespace=ca_namespace, release=ca_name, app="hlf-ca", verbose=verbose
        )
        ca_enroll(pod_exec)

        # Get CA Ingress and check it is running
        try:
            # Get ingress of CA
            ingress_urls = ingress_read(
                ca_name + "-hlf-ca", namespace=ca_namespace, verbose=verbose
            )
        except ApiException:
            print("No ingress found for CA")
            continue

        # Check the CA is running
        check_ca(ingress_host=ingress_urls[0], verbose=verbose)
