package micro

import (
	"context"
	"git.nspix.com/golang/micro/gateway/cli"
	"github.com/google/btree"
	"time"

	"git.nspix.com/golang/micro/gateway/http"
	"git.nspix.com/golang/micro/gateway/rpc"
	"git.nspix.com/golang/micro/registry"
)

const (
	EnvironmentDocker string = "docker"
	EnvironmentHost          = "host"
)

type (
	applicationKey struct {
	}

	handleEntry struct {
		Method  string `json:"method"`
		Func    HandleFunc
		Options []HandleOption
	}

	HandleTickerFunc func(ctx context.Context)

	tickPtr struct {
		sequence int64
		next     time.Time
		running  int32
		options  *TickOptions
		callback HandleTickerFunc
	}

	TickOptions struct {
		Context       context.Context
		Canceled      bool
		MustBeExecute bool
	}

	TickOption func(o *TickOptions)

	HandleOptions struct {
		DisableRpc  bool   //禁用RPC功能
		DisableHttp bool   //禁用HTTP功能
		DisableCli  bool   //禁用CLI功能
		HttpPath    string //重定向HTTP路由
		HttpMethod  string //HTTP路径
	}

	HandleOption func(o *HandleOptions)

	HandleFunc func(ctx Context) (err error)

	Application interface {
		Node() *registry.ServiceNode                                                           //获取节点信息
		HttpServe() *http.Server                                                               //获取HTTP实例
		RPCServe() *rpc.Server                                                                 //获取RPC实例
		CliServe() *cli.Server                                                                 //获取cli服务端
		PeekService(name string) ([]*registry.ServiceNode, error)                              //选择一个服务
		Handle(method string, cb HandleFunc, opts ...HandleOption)                             //注册一个处理器
		NewRequest(name, method string, body interface{}) (req *Request, err error)            //创建一个rpc请求
		DeferTick(duration time.Duration, callback HandleTickerFunc, opts ...TickOption) int64 //异步任务
		Environment() string
	}

	Server interface {
		Start(ctx context.Context) (err error)
		Stop() (err error)
	}
)

var (
	contextKey = applicationKey{}
)

func (p tickPtr) Less(i btree.Item) bool {
	q := i.(*tickPtr)
	if p.next.Before(q.next) {
		return true
	} else if p.sequence < q.sequence {
		return true
	}
	return false
}

func FromContext(ctx context.Context) Application {
	if v := ctx.Value(contextKey); v != nil {
		return v.(Application)
	}
	return nil
}

func WithContext(ctx context.Context, app Application) context.Context {
	return context.WithValue(ctx, contextKey, app)
}
