# coding=utf-8
# Licensed Materials - Property of IBM
# Copyright IBM Corp. 2019

import os
import streamsx.spl.op
import streamsx.spl.types
from streamsx.topology.schema import CommonSchema, StreamSchema
from streamsx.spl.types import rstring
import datetime
import json

PRIVATE_WML_TOOLKIT_NAMESPACE = "com.ibm.streams.wml"
PRIVATE_WML_TOOLKIT_LOCATION = "spl/toolkit.wml/com.ibm.streams.wml"

def _add_toolkit(topo):
    # specific private toolkit used in this wrapper
    # info.xml is an optional element -- so we don't provide for our private toolkit
    # toolkit.xml is generated during topology/application build -- so we don't care
    # So the only think is to provide the correct TK structure containing just the 
    # python file defining the primitive_operator, operator xml is also generated by topology/build
    # the toolkit is part of this streamsx.wml python package
    streamsx.spl.toolkit.add_toolkit(topo, os.path.dirname(os.path.realpath(__file__))+'/'+PRIVATE_WML_TOOLKIT_LOCATION)
    #topo.add_file_dependency( os.path.dirname(os.path.realpath(__file__))+'/'+PRIVATE_WML_TOOLKIT_LOCATION,"opt")


def wml_online_scoring( stream, 
                        deployment_guid, 
                        #mapping_function,
                        field_mapping,
                        credentials, 
                        space_guid, 
                        expected_load = 1000, 
                        queue_size = 2000,  
                        threads_per_node = 2, 
                        connectionConfiguration=None, 
                        name = None):
    """Scores tuples received from input stream using the online scoring endpoint of WML referenced by the deployment_guid.
    Models can be created and trained in Watson Studio or by using notebooks or by other tools in Cloud Pak for Data.

    Args:
    Returns:
        Stream: Tuples with same schema as input extended by the scoring result field 
        Error Stream: Tuples with same schema as input extended by the error indication
    """
    # add private toolkit
    topology = stream.topology
    _add_toolkit(topology)

    _op = _WMLOnlineScoring(stream = stream, 
                            schemas = [StreamSchema('tuple<blob __spl_po>'),StreamSchema('tuple<blob __spl_po>')],
                            deployment_guid = deployment_guid, 
                            #mapping_function = mapping_function,
                            field_mapping = field_mapping,
                            credentials = credentials, 
                            space_guid = space_guid, 
                            expected_load = expected_load, 
                            queue_size = queue_size,  
                            threads_per_node = threads_per_node, 
                            connectionConfiguration = connectionConfiguration, 
                            name = name)

    return _op.outputs[0],_op.outputs[1]




class _WMLOnlineScoring(streamsx.spl.op.Invoke):
    def __init__(self, stream, 
                       schemas, 
                       deployment_guid, 
                       #mapping_function,
                       field_mapping,
                       credentials, 
                       space_guid, 
                       expected_load, 
                       queue_size, 
                       threads_per_node, 
                       connectionConfiguration, 
                       name):

        topology = stream.topology
        kind="com.ibm.streams.wml::WMLOnlineScoring"
        inputs=[stream]
        schemas=schemas
        params = dict()
        params['deployment_guid'] = deployment_guid
        params['wml_credentials'] = credentials
        #params['mapping_function'] = mapping_function
        params['field_mapping'] = field_mapping,
        params['space_guid'] = space_guid
        params['expected_load'] = expected_load
        params['queue_size'] = queue_size
        params['threads_per_node'] = threads_per_node

        super(_WMLOnlineScoring, self).__init__(topology,kind,inputs,schemas,params,name)



def get_wml_credentials(token=None):
    """Returns a credential object to be used for WML connection
    
    Arguments:
    token -- token which should be included in the credentials
             this token has to be a non-expiring token as it is
             used at Streams runtime and no user credentials shall
             be needed resp. stored
             (default: users CPD token from Jupyter environment)
                 
    Call it only in the notebook where the topology is created, not in Python
    code executed at Streams runtime.
    """
    from icpd_core import icpd_util
        
    # take the token from notebook environment 
    if token is None:
        token = icpd_util.icpd_token
    if url is None:
        url = "https://internal-nginx-svc:12443"
    # credetials as to be used in CPD >=2.5
    credentials = {
                   "url": "https://internal-nginx-svc:12443", # access the main CP4D proxy/the CP4D cluster root from internal side
                   "token": token,
                   "instance_id": "wml_local",
                   "version" : "2.5.0"
                  }
    #test client creation to fail already in notebook if there is something wrong
    #need object copy here as the function changes "instance_id" in the object and so it 
    #couldn't be used anymore afterwards
    #wml_client = WatsonMachineLearningAPIClient(copy.copy(credentials))
    return credentials
    
def get_project_space(credentials):
    """Returns the notebooks project space GUID.
       
    Argument:
    credentials -- the credentials to be used to connect to WML
      
    Call it only in the notebook where the topology is created, not at Streams runtime.
    Models and deployments are placed in projects space if no other space is given at 
    their creation time.
    The space GUID is needed to instantiate a WMLOnlineScoring object.
    """
    from project_lib import Project
        
    wml_client = WatsonMachineLearningAPIClient(copy.copy(credentials))
    spaces = wml_client.spaces.get_details()["resources"]
    project = Project.access()
    project_guid = project.get_metadata()["metadata"]["guid"]
    # get the space associated with the project
    project_space=None
    for space in spaces:
        for tag in space["entity"]["tags"]:
            if tag["value"]=="dsx-project."+project_guid:
                project_space = space["metadata"]["id"]
    return project_space

