#
# Copyright 2019-2020 VMware, Inc.  All rights reserved. -- VMware Confidential
#
import os
import sys
import ssl
import logging
sys.path.append(os.path.dirname(__file__))
from pyVmomi import lookup #pylint: disable=E0401,E0611
from pyVmomi import SoapStubAdapter #pylint: disable=E0401

logger = logging.getLogger(__name__)


class LookupServiceError(Exception):
    pass


class LookupService:
    """
    Lookup Service client for easier discovery of service registration
    """
    def __init__(self, ls_url, no_ssl_verification=False):
        """
        Create new instance of LookupService

        :param ls_url: Lookup service url.
        Example: https://sof2-l7-1019.eng.vmware.com/lookupservice/sdk
        :type ls_url: str
        """
        if no_ssl_verification:
            context = ssl._create_unverified_context()
        else:
            context = ssl.create_default_context()

        logger.info("Creating LookupService client with URL: %s", ls_url)
        try:
            self._stub = SoapStubAdapter(url=ls_url, ns="lookup/2.0",
                                         sslContext=context)
            self._si = lookup.ServiceInstance("ServiceInstance",
                                              self._stub)
            self.content = self._si.RetrieveServiceContent()
        except Exception:
            logger.exception("Failed to create LookupService stub")
            raise LookupServiceError("Failed to create LookupService "
                                     "stub with URL {}".format(ls_url))

    @staticmethod
    def create_filter(product_id=None, service_type=None,
                      ep_protocol=None, ep_type=None):
        """
        Creates filter which can be used when querying LookupService

        :param product_id:  If provided the query fill look for services
         that match this product id
        :type product_id: str

        :param service_type: If provided the query fill look for services
        that match this service type
        :type service_type

        :param ep_protocol: The end point communication protocol
        :type ep_protocol: str

        :param ep_type: Service end point type identifier
        (Java package-style naming)
        :type ep_type: str

        :return: Returns filter with the specified options
        :rtype: lookup.serviceRegistration.Filter
        """
        filter_criteria = lookup.serviceRegistration.Filter()
        filter_criteria.serviceType = lookup.ServiceRegistration.ServiceType()
        filter_criteria.endpointType = \
            lookup.ServiceRegistration.EndpointType()

        if product_id is not None:
            filter_criteria.serviceType.product = product_id

        if service_type is not None:
            filter_criteria.serviceType.type = service_type

        if ep_protocol is not None:
            filter_criteria.endpointType.protocol = ep_protocol

        if ep_type is not None:
            filter_criteria.endpointType.type = ep_type

        return filter_criteria

    def get_services_list(self, filter_criteria=None):
        """
        Retrieves all service registrations

        :param filter_criteria: If provided this filter will be
         used when querying LookupService
        :type filter_criteria: lookup.serviceRegistration.Filter

        :return: List of service registrations
        :rtype: list of lookup.ServiceRegistration.Info
        """
        if filter_criteria is None:
            filter_criteria = LookupService.create_filter()

        result = []

        try:
            result = self.content.serviceRegistration.List\
                (filterCriteria=filter_criteria)
        except Exception:
            logger.exception("Failed to list service registrations")
            raise LookupServiceError("Failed to list service registrations")

        return result

    def get_service(self, service_id):
        result = None

        try:
            result = self.content.serviceRegistration.Get(service_id)
        except Exception:
            logger.exception("Failed to get service registration "
                             "with id %s", service_id)
            raise LookupServiceError("Failed to get service registration "
                                     "with id {}".format(service_id))

        return result
