"""
Addition of VMTX privileges
"""

__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2019 VMware, Inc. All rights reserved.'

import os
import sys

import logging
import warnings

vmware_python_path = os.getenv('VMWARE_PYTHON_PATH')
if vmware_python_path and os.path.exists(vmware_python_path):
    sys.path.append(vmware_python_path)

from cis.cisreglib import (AuthzClient, CisregOptionParser,
                           LookupServiceClient, SsoClient, _get_syscfg_info)

CLS_ADMIN_NAME_PREFIX = 'Content library administrator'
CLS_ADMIN_NAME_ID_PREFIX='com.vmware.Content.Admin'
from patches.constants import (
    AUTHZ_TYPE_ID,
    CONTENT_LIBRARY_CONFIG_HOME, CONTENT_LIBRARY_HOME, CONTENT_LIBRARY_SERVICE_SPEC,
    CONTENT_LIBRARY_SERVICE_REGISTER_SPEC, EP_AUTHZ_PROTOCOL, EP_AUTHZ_TYPE_ID, KEY_STORE_NAME_MACHINE,
    REVERSE_PROXY_ADDRESS_KEY, REVERSE_PROXY_CONNECTION_TYPE_KEY,
    REVERSE_PROXY_CONNECTION_TYPE_LOCAL, SOLUTION_USER_NAME_KEY, SOLUTION_USER_ID_KEY)

logger = logging.getLogger(__name__)
sys.path.append('/usr/lib/vmware-vmafd/lib64')

# Suppress warnings coming from vmafd and identity imports.
with warnings.catch_warnings():
    warnings.simplefilter('ignore', RuntimeWarning)
    from identity.vmkeystore import VmKeyStore

sys.path.append(os.path.dirname(__file__))


VMTX_SYNC_PRIVILEGES = ['ContentLibrary.PublishLibrary', 'ContentLibrary.PublishLibraryItem',
                        'ContentLibrary.AddSubscription', 'ContentLibrary.UpdateSubscription',
                        'ContentLibrary.DeleteSubscription']

sso_client = None
authz_client = None


def init_authz():
    global sso_client
    global authz_client
    ls_url, domain_name = _get_syscfg_info()
    logger.info("Connecting to Lookup Service using %s" % ls_url)
    ls_obj = LookupServiceClient(ls_url, retry_count=1)
    sts_url, sts_cert_data = ls_obj.get_sts_endpoint_data()

    with VmKeyStore('VKS') as ks:
        ks.load(KEY_STORE_NAME_MACHINE)
        cert = ks.get_certificate(KEY_STORE_NAME_MACHINE)
        key = ks.get_key(KEY_STORE_NAME_MACHINE)

    sso_client = SsoClient(sts_url, sts_cert_data, None, None, cert=cert, key=key)
    ls_obj.set_sso_client(sso_client)
    authz_endpoints = ls_obj.get_service_endpoints(
                       AUTHZ_TYPE_ID, ep_protocol=EP_AUTHZ_PROTOCOL,
                       ep_type=EP_AUTHZ_TYPE_ID, local_nodeid=None)
    authz_client = AuthzClient(authz_endpoints[0].url, sso_client)


def get_cls_admin_role():
    for role_obj in authz_client._authz_service.GetRoles():
        logger.info("role.name = %s, role.id = %s" % (role_obj.name, role_obj.id))
        if role_obj.name.startswith(CLS_ADMIN_NAME_PREFIX) or role_obj.name.startswith(CLS_ADMIN_NAME_ID_PREFIX):
            log("CLS Admin role name = %s" % role_obj.name)
            return role_obj
    return None


def register_cls():
    sys.path.append(CONTENT_LIBRARY_HOME)

    from install_lib.cis_register import RegCIS

    service_register_properties = {}
    with open(CONTENT_LIBRARY_SERVICE_REGISTER_SPEC) as f:
        for line in f.readlines():
            if "=" in line:
                key, value = line.rstrip("\n").split("=")
                service_register_properties[key.strip()] = value.strip()

    solution_user_name = None
    solution_user_id = None
    reverse_proxy_address = None
    for key, value in service_register_properties.items():
        if key == SOLUTION_USER_NAME_KEY:
            solution_user_name = value
        elif key == SOLUTION_USER_ID_KEY:
            solution_user_id = value
        elif key == REVERSE_PROXY_ADDRESS_KEY:
            reverse_proxy_address = value
        elif key == REVERSE_PROXY_CONNECTION_TYPE_KEY:
            reverse_proxy_connection_type = value
            if reverse_proxy_connection_type != REVERSE_PROXY_CONNECTION_TYPE_LOCAL:
                raise Exception("proxy connection type should be local in a patch setup!")

    logger.info("Re-registering CL service with lookup service")
    logger.info("Using solution user name: %s, solution user id: %s, reverse proxy address: %s",
                solution_user_name, solution_user_id, reverse_proxy_address)

    # Note: This is a re-registration by specifying is_patch as true, and reverse proxy address for
    #       local connection is the port only
    reg_info = RegCIS(CONTENT_LIBRARY_HOME, services_spec=CONTENT_LIBRARY_SERVICE_SPEC,
                      vdc_cfg_dir=CONTENT_LIBRARY_CONFIG_HOME,
                      service_http_port=reverse_proxy_address, is_patch=True,
                      key_store_name=KEY_STORE_NAME_MACHINE)
    reg_info.registerAll(solution_user_name, solution_user_id)
    logger.info("Reregistration successful")


def add_privileges():
    global authz_client
    if authz_client is None:
        init_authz()

    # First 'try' Content Library reregistration to get the latest deployed privilege file
    register_cls()

    cls_privileges_xml_file = '/etc/vmware-content-library/metadata/cls_privilege.xml'
    cisreg_options = {'permission.newPrivilege': cls_privileges_xml_file}

    cisreg_opt_parser = CisregOptionParser(cisreg_options)
    privileges_list = cisreg_opt_parser.get_privs()
    vmtx_sync_privileges = []
    for privilege in privileges_list:
        if privilege.id in VMTX_SYNC_PRIVILEGES:
            vmtx_sync_privileges.append(privilege)
    logger.info("Adding VMTX Sync privileges [%s]" % ' '.join(priv.id for priv in vmtx_sync_privileges))
    # load_priv() adds all the privileges in the list, that don't already exist
    authz_client.load_privs(vmtx_sync_privileges)

    cls_admin_role = get_cls_admin_role()
    logger.info("Adding privileges [%s] to role %s" % (' '.join(VMTX_SYNC_PRIVILEGES), cls_admin_role.name))
    # Using set(...) is unnecessary precaution, as update_role() guards against duplicates
    update_role(authz_client, cls_admin_role, list(set(cls_admin_role.privilegeId + VMTX_SYNC_PRIVILEGES)))


def update_role(authz_client, role, priv_ids):
    new_role_obj = dataservice.accesscontrol.Role(id=role.id, name=role.name, description=role.description,
                                                  privilegeId=priv_ids)
    logger.info("new_role.name = %s, new_role.id = %s" % (new_role_obj.name, new_role_obj.id))
    authz_client._authz_service.UpdateRole(new_role_obj)


if __name__ == '__main__':
    add_privileges()
