package nodes

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/robertkrimen/otto"
	"sparrow/pkg/protocol"
	"sparrow/pkg/ruleEngine"
	"sparrow/pkg/server"
	"sync"
)

const jsWrapperPrifixTemplate = `function %s(msgStr, metaDataStr, msgType) { 
if(!metaData === undefined)
      metaData = {}   
if(!msgStr === undefined)
      msgStr = {}
if(!metaDataStr === undefined)
      metaDataStr = {}
var msg = JSON.parse(msgStr);
   var metaData = JSON.parse(metaDataStr);
   if(!metaData === undefined)
      metaData = {}
   return %s(msg, metaData, msgType);
   function %s(%s, %s, %s) {`
const jsWrapperSuffix = `}}`
const ruleNodeFuncName = "ruleNodeFunc"

// FilterJavascriptNode js代码逻辑节点，提供执行Js代码的执行能力，依赖执行结果输出节点的最终判定，脚本返回true或false
// 默认Filter函数接收三个参数，Filter(msg, metadata, msgType)
type FilterJavascriptNode struct {
	vm     *otto.Otto
	config *FilterJavascriptNodeConfig
	l      sync.Mutex
}

func (j *FilterJavascriptNode) Init(ctx ruleEngine.Context, config string) error {
	if config != "" {
		c := new(FilterJavascriptNodeConfig)
		err := json.Unmarshal([]byte(config), c)
		if err != nil {
			return err
		}
		j.config = c
	}
	j.vm = otto.New()
	_, err := j.vm.Run(generateRuleNodeScript("filter", j.config.FuncBody))
	if err != nil {
		return err
	}
	return nil
}

func (j *FilterJavascriptNode) OnMessage(ctx ruleEngine.Context, message *protocol.Message) error {
	body := message.Data
	metaData, err := json.Marshal(message.MetaData)
	if err != nil {
		server.Log.Errorf("metadata marshal error:%s", err.Error())
		next := j.processError(ctx, message, err)
		ctx.TellError(next, err)
		return errors.New("metadata marshal error " + err.Error())
	}
	j.l.Lock()
	defer j.l.Unlock()
	res, err := j.vm.Call("filter", nil, body, string(metaData), message.Type)
	if err != nil {
		//next := j.processError(ctx, message, err)
		//ctx.TellError(next, err)
		server.Log.Errorf("vm call filter error:%s", err.Error())
		fmt.Printf("________++++==%s", metaData)
		return err
	}
	v := false
	if result, err := res.ToBoolean(); err == nil {
		v = result
	}

	if v {
		ctx.TellNext(message, protocol.True)
	} else {
		ctx.TellNext(message, protocol.False)
	}
	return nil
}

func (j *FilterJavascriptNode) processError(ctx ruleEngine.Context, msg *protocol.Message, err error) *protocol.Message {
	var metaData map[string]interface{}
	if msg.MetaData != nil {
		metaData = msg.MetaData
	}
	metaData = make(map[string]interface{})
	metaData["error"] = err.Error()

	return ctx.TransformMessage(msg, msg.Type, msg.Originator, metaData, msg.Data)
}

// FilterJavascriptNodeConfig Js 节点配置
type FilterJavascriptNodeConfig struct {
	FuncBody string `json:"func_body"` // 函数体代码
}

func generateRuleNodeScript(funcName string, scriptBody string, args ...string) string {
	var msgArg, metaDataArg, msgTypArg string
	if len(args) == 3 {
		msgArg = args[0]
		metaDataArg = args[1]
		msgTypArg = args[2]
	} else {
		msgArg = "msg"
		msgTypArg = "msgType"
		metaDataArg = "metadata"
	}
	jsContent := fmt.Sprintf(jsWrapperPrifixTemplate, funcName,
		ruleNodeFuncName, ruleNodeFuncName, msgArg, metaDataArg, msgTypArg)
	return fmt.Sprintf("%s%s%s", jsContent, scriptBody, jsWrapperSuffix)
}
