package router

import (
	"bp.jydev.jianyu360.cn/BaseService/gateway/common/db"
	"bp.jydev.jianyu360.cn/BaseService/gateway/common/enum"
	. "bp.jydev.jianyu360.cn/BaseService/gateway/common/gatecode"
	"fmt"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/net/gtrace"
	"github.com/gogf/gf/v2/os/gctx"
	"github.com/gogf/gf/v2/util/gconv"
	"log"
	"regexp"
	"strings"
)

type Manager struct {
	eqRouters   map[string]*Router
	regexRouter map[*regexp.Regexp]*Router
}

// InitRouterManager 初始化系统代理路由
// 支持完全匹配和正则匹配
func InitRouterManager() (*Manager, error) {
	//无权限地址
	urlSwitch := g.Cfg().MustGet(gctx.New(), "noPowerUrlSwitch").MapStrStr()
	//加载规则
	res := db.GateWatMySql.Query(fmt.Sprintf("SELECT status,middleground_code,url,function_code,check_sess,check_power,check_auth,check_status,check_blacklist,ploy_code,timeout,remark,appid,deduct_source,power_type FROM %s",
		g.Cfg().MustGet(gctx.New(), "system.routerTable", "front_proxy").String()))
	if res == nil || len(*res) == 0 {
		return nil, fmt.Errorf("未发现可用路由")
	}
	// 初始化 routerManager
	routerManager := &Manager{
		eqRouters:   make(map[string]*Router),
		regexRouter: make(map[*regexp.Regexp]*Router),
	}

	for _, row := range *res {
		// 获取路由信息
		router := gconv.String(row["url"])
		signCode := gconv.String(row["middleground_code"])
		routerRule := &Router{
			Status:       gconv.Int(row["status"]),
			PowerCheck:   gconv.Int(row["check_power"]),
			SessCheck:    enum.NewSessCheck(gconv.Int64(row["check_sess"])),
			AccountCheck: enum.NewAccountCheck(gconv.Int64(row["check_status"])),
			AuthCheck:    enum.NewAuthCheck(gconv.Int64(row["check_auth"])),
			BlackCheck:   gconv.Int(row["check_blacklist"]) == 1,
			LimitPloy:    gconv.String(row["ploy_code"]), //策略
			Deduct:       gconv.Int(row["deduct_source"]),
			FuncCode:     gconv.String(row["function_code"]),
			MiddleCode:   signCode,
			AppId:        gconv.String(row["appid"]),
			ReqUrl:       router,
			IsOutServer:  strings.HasPrefix(signCode, "http://") || strings.HasPrefix(signCode, "https://"),
			TimeOut:      gconv.Int64(row["timeout"]),
			Remark:       gconv.String(row["remark"]),
			PowerType:    gconv.Int(row["power_type"]),
			NoPowerUrl:   urlSwitch[router],
		}

		// 判断路由匹配方式是完全匹配还是正则匹配 (此处逻辑参考x-web框架)
		if regexp.QuoteMeta(router) == router {
			routerManager.eqRouters[router] = routerRule
		} else {
			reg, err := regexp.Compile(router)
			if err != nil {
				log.Printf("路由%s装载异常 %v\n", router, err)
			}
			routerManager.regexRouter[reg] = routerRule
		}
	}
	return routerManager, nil
}

// GetRouterRule 获取路由规则
// 根据用户请求地址匹配路由规则，优先绝对匹配后用正则匹配。
func (m *Manager) GetRouterRule(url string) (*Router, error) {
	routerRule, exists := m.eqRouters[url]
	if !exists {
		for reg, thisRouterRule := range m.regexRouter {
			if reg.MatchString(url) {
				routerRule = thisRouterRule
				break
			}
		}
	}
	if routerRule == nil {
		return nil, NewErrorWithCode(GATEWAY_ROUTER_NOTFIND, fmt.Sprintf("未找到请求地址%s,请检查是否注册到数据库\n", url))
	}
	// 路由状态判断
	if routerRule.Status != 1 {
		return nil, NewErrorWithCode(GATEWAY_ROUTER_UPHOLD, fmt.Sprintf("接口状态：%d\n", routerRule.Status))
	}
	return routerRule, nil
}

// InfusionContext 注入通用结构体gContext
func (m *Manager) InfusionContext(r *ghttp.Request) (err error) {
	_, span := gtrace.NewSpan(r.Context(), "InfusionContext")
	defer span.End()
	//r.SetCtx(ctx)

	var router *Router
	var GCtx = &GContext{
		Sess:       &JySession{},
		RouterRule: &Router{},
	}
	router, err = m.GetRouterRule(r.URL.Path)
	if err != nil {
		r.SetCtxVar(GContextKey, GCtx)
		return
	}
	GCtx.RouterRule = router
	//获取session
	jySess, _ := InitJySessionContext(r)
	GCtx.Sess = jySess
	r.SetCtxVar(GContextKey, GCtx)
	return
}
