package web

import (
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"net/http"
	"time"

	"gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/abtest"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/context"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/service"
)

type DataSourceInfo struct {
	Type      string `json:"type"`
	AccessId  string `json:"access_id"`
	AccessKey string `json:"access_key"`
	Endpoint  string `json:"endpoint"`
	Project   string `json:"project"`
	Topic     string `json:"topic"`
}
type FeatureReplyParam struct {
	Scene        string         `json:"scene"`
	RequestId    string         `json:"request_id"`
	UserId       string         `json:"user_id"` // user id
	ItemId       string         `json:"item_id"` // item id
	UserFeatures string         `json:"user_features"`
	ItemFeatures string         `json:"item_features"`
	DataSource   DataSourceInfo `json:"datasource"`
}

func (r *FeatureReplyParam) GetParameter(name string) interface{} {
	if name == "uid" {
		return r.UserId
	} else if name == "scene" {
		return r.Scene
	} else if name == "datasource_type" {
		return r.DataSource.Type
	} else if name == "access_id" {
		return r.DataSource.AccessId
	} else if name == "access_key" {
		return r.DataSource.AccessKey
	} else if name == "endpoint" {
		return r.DataSource.Endpoint
	} else if name == "project" {
		return r.DataSource.Project
	} else if name == "topic" {
		return r.DataSource.Topic
	} else if name == "item_id" {
		return r.ItemId
	}

	return nil
}

type FeatureReplyResponse struct {
	Response
}

func (r *FeatureReplyResponse) ToString() string {
	j, _ := json.Marshal(r)
	return string(j)
}

type FeatureReplyController struct {
	Controller
	param   FeatureReplyParam
	context *context.RecommendContext
}

func (c *FeatureReplyController) Process(w http.ResponseWriter, r *http.Request) {
	c.Start = time.Now()
	var err error
	c.RequestBody, err = ioutil.ReadAll(r.Body)
	if err != nil {
		c.SendError(w, ERROR_PARAMETER_CODE, "read parammeter error")
		return
	}
	if len(c.RequestBody) == 0 {
		c.SendError(w, ERROR_PARAMETER_CODE, "request body empty")
		return
	}
	c.LogRequestBegin(r)
	if err := c.CheckParameter(); err != nil {
		c.SendError(w, ERROR_PARAMETER_CODE, err.Error())
		return
	}
	c.doProcess(w, r)
	c.End = time.Now()
	c.LogRequestEnd(r)
}
func (r *FeatureReplyController) CheckParameter() error {
	if err := json.Unmarshal(r.RequestBody, &r.param); err != nil {
		return err
	}

	if len(r.param.UserId) == 0 {
		return errors.New("user_id not empty")
	}
	if r.param.ItemId == "" {
		return errors.New("item_id not empty")
	}

	if r.param.RequestId == "" {
		return errors.New("request_id not empty")
	}

	r.RequestId = r.param.RequestId
	return nil
}
func (c *FeatureReplyController) doProcess(w http.ResponseWriter, r *http.Request) {
	c.makeRecommendContext()
	featureReplyService := service.NewFeatureReplyService()

	featureReplyService.FeatureReply(c.param.UserFeatures, c.param.ItemFeatures, c.context)

	response := FeatureReplyResponse{
		Response: Response{
			RequestId: c.RequestId,
			Code:      200,
			Message:   "success",
		},
	}

	io.WriteString(w, response.ToString())
}

func (c *FeatureReplyController) makeRecommendContext() {
	c.context = context.NewRecommendContext()
	c.context.Param = &c.param
	c.context.RecommendId = c.RequestId
	c.context.Config = recconf.Config

	abcontext := model.ExperimentContext{
		Uid:          c.param.UserId,
		RequestId:    c.RequestId,
		FilterParams: map[string]interface{}{},
	}

	if abtest.GetExperimentClient() != nil {
		c.context.ExperimentResult = abtest.GetExperimentClient().MatchExperiment(c.param.Scene, &abcontext)
	}
}
