package cool

import (
	"time"

	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/text/gstr"
)

type CoolFunc interface {
	// Func handler
	Func(ctx g.Ctx, param string) (err error)
	// IsSingleton 是否单例,当为true时，只能有一个任务在执行,在注意函数为计划任务时使用
	IsSingleton() bool
	// IsAllWorker 是否所有worker都执行
	IsAllWorker() bool
}

// FuncMap 函数列表
var FuncMap = make(map[string]CoolFunc)

// RegisterFunc 注册函数
func RegisterFunc(name string, f CoolFunc) {
	FuncMap[name] = f
}

// GetFunc 获取函数
func GetFunc(name string) CoolFunc {
	return FuncMap[name]
}

// RunFunc 运行函数
func RunFunc(ctx g.Ctx, funcstring string) (err error) {
	funcName := gstr.SubStr(funcstring, 0, gstr.Pos(funcstring, "("))
	funcParam := gstr.SubStr(funcstring, gstr.Pos(funcstring, "(")+1, gstr.Pos(funcstring, ")")-gstr.Pos(funcstring, "(")-1)
	if _, ok := FuncMap[funcName]; !ok {
		err = gerror.New("函数不存在:" + funcName)
		return
	}
	if !FuncMap[funcName].IsAllWorker() {
		// 检查当前是否为主进程, 如果不是主进程, 则不执行
		if ProcessFlag != CacheManager.MustGetOrSet(ctx, "cool:masterflag", ProcessFlag, 60*time.Second).String() {
			Loger.Debug(ctx, "当前进程不是主进程, 不执行单例函数", funcName)
			return
		}
	}
	err = FuncMap[funcName].Func(ctx, funcParam)
	return
}

// ClusterRunFunc 集群运行函数,如果是单机模式, 则直接运行函数
func ClusterRunFunc(ctx g.Ctx, funcstring string) (err error) {
	if IsRedisMode {
		conn, err := g.Redis("cool").Conn(ctx)
		if err != nil {
			return err
		}
		defer conn.Close(ctx)
		_, err = conn.Do(ctx, "publish", "cool:func", funcstring)
		return err
	} else {
		return RunFunc(ctx, funcstring)
	}
}

// ListenFunc 监听函数
func ListenFunc(ctx g.Ctx) {
	if IsRedisMode {
		conn, err := g.Redis("cool").Conn(ctx)
		if err != nil {
			panic(err)
		}
		defer conn.Close(ctx)
		_, err = conn.Do(ctx, "subscribe", "cool:func")
		if err != nil {
			panic(err)
		}
		for {
			data, err := conn.Receive(ctx)
			if err != nil {
				Loger.Error(ctx, err)
				time.Sleep(10 * time.Second)
				continue
			}
			if data != nil {
				dataMap := data.MapStrStr()
				if dataMap["Kind"] == "subscribe" {
					continue
				}
				if dataMap["Channel"] == "cool:func" {
					Loger.Debug(ctx, "执行函数", dataMap["Payload"])
					err := RunFunc(ctx, dataMap["Payload"])
					if err != nil {
						Loger.Error(ctx, "执行函数失败", err)
					}
				}
			}
		}
	} else {
		panic(gerror.New("集群模式下, 请使用Redis作为缓存"))
	}
}
