package pairec

import (
	"flag"
	"io"
	"net/http"
	"os"

	"github.com/prometheus/client_golang/prometheus/promhttp"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/abtest"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/config"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/datasource"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/datasource/datahub"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/datasource/hbase"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/filter"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/holo"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/mysqldb"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/redisdb"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/tablestoredb"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/service"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/service/rank"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/sort"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/web"
)

type hookfunc func() error

var (
	hooks = make([]hookfunc, 0)
)
var configFile string

func init() {
	flag.StringVar(&configFile, "config", "", "config file path")
	flag.BoolVar(&config.AppConfig.WarmUpData, "warm-up-data", false, "create eas warm up data flag")
}
func AddStartHook(hf ...hookfunc) {
	hooks = append(hooks, hf...)
}
func Run() {
	mode := os.Getenv("RUN_MODE")
	if mode != "COMMAND" {
		flag.Parse()
	}

	// load config
	if len(configFile) == 0 {
		configFile = os.Getenv("CONFIG_PATH")
		if configFile == "" {
			panic("config file path empty")
		}
	}
	err := recconf.Load(configFile)
	if err != nil {
		panic(err)
	}

	registerRouteInfo()

	runStartHook()

	PairecApp.Run()
}

func runBeforeStart() {
	mysqldb.Load(recconf.Config)
	redisdb.Load(recconf.Config)
	tablestoredb.Load(recconf.Config)
	datasource.Load(recconf.Config)
	datahub.Load(recconf.Config)
	hbase.Load(recconf.Config)
	holo.Load(recconf.Config)
	abtest.Load(recconf.Config)
	algorithm.Load(recconf.Config) // holo must be loaded before loading some algorithm
	register(recconf.Config)
}
func runStartHook() {
	runBeforeStart()

	// first register hook
	AddStartHook(func() error {
		filter.Load(recconf.Config)
		sort.Load(recconf.Config)
		// gdb.Load(recconf.Config)
		service.Load(recconf.Config)
		service.LoadFeatureConfig(recconf.Config)
		service.LoadWithConfig(recconf.Config)
		rank.LoadColdStartRankConfig(recconf.Config)
		// clean log dir
		ClearDir(recconf.Config.LogConf)

		return nil
	})

	for _, hf := range hooks {
		if err := hf(); err != nil {
			panic(err)
		}
	}
}
func registerRouteInfo() {
	// use for listen http server state
	HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, "success")
	})

	// register recommend Controller
	Route("/api/recommend", &web.RecommendController{})
	Route("/api/recall", &web.UserRecallController{})
	Route("/api/callback", &web.CallBackController{})
	Route("/api/feature_reply", &web.FeatureReplyController{})
	HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) {
		promhttp.Handler().ServeHTTP(w, r)
	})
}
