#
# Copyright 2019-2020 VMware, Inc.  All rights reserved. -- VMware Confidential
#
import logging
import os, sys
sys.path.append(os.path.dirname(__file__))
from service_base import ServiceStub, DEFAULT_HTTPS_PORT
from lookup_service import LookupService
from .utils.ls_utils import get_sts_url # pylint: disable=E0402
from .utils.authentication import CertificateStore # pylint: disable=E0402


from pyVmomi import Vim  #pylint: disable=E0401,E0611

logger = logging.getLogger(__name__)


class VcAuthenticationError(Exception):
    pass


class VcSeriveError(Exception):
    pass


class VcService(ServiceStub):
    """
    Provides functionality that helps working with the
    VMware vSphere API python binding
    """
    SERVICE_PATH = "/sdk"

    def __init__(self, host, port=DEFAULT_HTTPS_PORT,
                 username=None, password=None,
                 cert_file=None, key_file=None,
                 sts_url=None, no_ssl_verification=False):
        """
        Creates new instance of VcService

        @param host: Hostname or IP address of the vCenter Server
        @type host: str

        @param username: SSO username to log in with
        @type username: str

        @param password: Password for the SSO user
        @type password: type

        @param cert_file: Path to the certificate file
        @type cert_file: str

        @param key_file: Path to the certificate key file
        @type key_file: str

        @param sts_url: STS endpoint URL
        @type sts_url: str

        @param port: Port number used by the vCenter Server
        @type port: int

        @param no_ssl_verification: Skips SSL verification when set to True
        @type no_ssl_verification: bool
        """
        logger.info("Creating VcService client on host %s", host)
        super(VcService, self).__init__(host, username=username,
                                        password=password,
                                        cert_file=cert_file,
                                        key_file=key_file,
                                        sts_url=sts_url,
                                        port=port,
                                        path=self.SERVICE_PATH,
                                        no_ssl_verification=no_ssl_verification)
        self.si = Vim.ServiceInstance("ServiceInstance", self.stub)

    def get_uuid(self):
        """
        Return the UUID of the vCenter
        which is stored in the AboutInfo data object
        @rtype: str
        """
        return self.si.content.about.instanceUuid

    def logout(self):
        try:
            self.si.content.sessionManager.Logout()
        except Vim.fault.InvalidLogin:
            logger.error("Cannot logout from host %s "
                         "since no login was performed", self.host)

    def RetrieveContent(self):
        try:
            # This will trigger the internal login
            self.si.RetrieveContent()
            return self.si.RetrieveContent()
        except Vim.fault.InvalidLogin as e:
            logger.error(str(e))
            raise VcAuthenticationError("Unable to authenticate to host {} "
                                        "and retrieve ServiceInstance "
                                        "content".format(self.host))
        except Exception as e:  # pylint: disable=W0703
            logger.exception("Unknown exception during "
                             "retrieving of service content")
            raise VcSeriveError(str(e))

def getVCServiceFromCertificate(cert_store):
    '''
    A factory method for creating vCenter service
    stub as handle all its dependencies using
    certificate for authentication

    @param cert_store: A certificate store required
    for creating vc_service instance.
    @type cert_store:
    services.utils.authentication.CertificateStore
    '''
    from cis.cisreglib import VmafdClient  # pylint: disable=E0611,E0401
    vmafd_client = VmafdClient()
    ls_url = vmafd_client.get_ls_location()
    ls_client = LookupService(ls_url)
    sts_url = get_sts_url(ls_client)
    hostname = vmafd_client.get_pnid()
    port = _getVcPort()
    vc_service = VcService(hostname,
                           port,
                           key_file=cert_store.get_key_file(),
                           cert_file=cert_store.get_cert_file(),
                           sts_url=sts_url)
    return vc_service

def _getVcPort():
    ''' VC can have custom port for the rhttp port and this function tries to
    find the correct one
    '''
    try:
        from cis.tools import get_install_parameter
    except ImportError:
        logger.info("Cannot import get_install_parameter, "
                    "will return default value")
        return 443
    vcPort = int(get_install_parameter("rhttpproxy.ext.port2", "443"))
    logger.info("Port found: %s", vcPort)
    return vcPort

def getVCService(hostname=None, username=None, password=None,
                 port=None, no_ssl_verification=True):
    '''
    A factory method for creating a vCenter service
     stub based on the input parameters
    if username and password is set it uses them for authentication
    else it creates instance using certificate and ignores the input params. 

    @param hostname: Hostname or IP address of the vCenter Server
    @type hostname: str

    @param username: SSO username to log in with
    @type username: str

    @param password: Password for the SSO user
    @type password: type

    @param no_ssl_verification: Skips SSL verification when set to True
    @type no_ssl_verification: bool

    @param port: The port of the rhttp proxy
    @type port: int
    '''

    if username is not None and password is not None:
        port = port or _getVcPort()
        return VcService(hostname, port, username, password,
                         no_ssl_verification=no_ssl_verification)
    else:
        return getVCServiceFromCertificate(CertificateStore())



