package beego

import (
	"fmt"
	"github.com/beego/beego/v2/core/logs"
	"github.com/beego/beego/v2/server/web"
	"github.com/beego/beego/v2/server/web/context"
	"github.com/linmadan/egglib-go/web/beego/filters"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/constant"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/api/authlib"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/port/beego/controllers"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	. "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/log"
	_ "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/port/beego/routers"
)

func init() {
	web.BConfig.AppName = "character-library-metadata-bastion"
	web.BConfig.CopyRequestBody = true
	web.BConfig.RunMode = "dev" //"prod"
	web.BConfig.Listen.HTTPPort = 8080
	web.BConfig.Listen.EnableAdmin = false
	web.BConfig.WebConfig.CommentRouterPath = "/pkg/port/beego/routers"
	web.BConfig.Log.AccessLogs = true
	if os.Getenv("RUN_MODE") != "" {
		web.BConfig.RunMode = os.Getenv("RUN_MODE")
	}
	if os.Getenv("HTTP_PORT") != "" {
		portStr := os.Getenv("HTTP_PORT")
		if port, err := strconv.Atoi(portStr); err == nil {
			web.BConfig.Listen.HTTPPort = port
		}
	}

	//https支持
	web.BConfig.Listen.EnableHTTPS = true
	web.BConfig.Listen.HTTPSPort = 443

	web.BConfig.Listen.HTTPSCertFile = "./config/fjmaimaimai.com_bundle.crt"
	web.BConfig.Listen.HTTPSKeyFile = "./config/fjmaimaimai.com.key"

	//进程内监控
	//web.BConfig.Listen.EnableAdmin = true
	//web.BConfig.Listen.AdminPort = 8088
	if os.Getenv("HTTPS_PORT") != "" {
		portStr := os.Getenv("HTTPS_PORT")
		if port, err := strconv.Atoi(portStr); err == nil {
			web.BConfig.Listen.HTTPSPort = port
		}
	}

	web.InsertFilter("/*", web.BeforeRouter, filters.AllowCors())
	web.InsertFilter("/*", web.BeforeRouter, JwtFilter())
	web.InsertFilter("/*", web.BeforeRouter, RequestCostBefore())
	web.InsertFilter("/*", web.BeforeExec, controllers.BlacklistFilter(controllers.BlacklistRouters))
	web.InsertFilter("/*", web.BeforeExec, CreateRequestLogFilter(true)) //  filters.CreateRequstLogFilter(Logger)
	if constant.SERVICE_ENV == "dev" {                                   //|| web.BConfig.RunMode =="test"
		web.InsertFilter("/*", web.AfterExec, filters.CreateResponseLogFilter(Logger), web.WithReturnOnOutput(false))
	}
	web.InsertFilter("/*", web.AfterExec, RequestCostAfter(150), web.WithReturnOnOutput(false))
}

func CreateRequestLogFilter(console bool) func(ctx *context.Context) {
	return func(ctx *context.Context) {
		msg := fmt.Sprintf("beego | %v | %v | %v \n %v", ctx.Input.Method(), strings.Split(ctx.Request.RemoteAddr, ":")[0], ctx.Input.URL(), string(ctx.Input.RequestBody))
		logs.Debug(msg)
		if console {
			fmt.Println(msg)
		}
	}
}

func JwtFilter() func(ctx *context.Context) {
	authLib := authlib.NewApiAuthLib(constant.AUTH_SERVER_HOST)
	authLib.BaseServiceGateway.ConnectTimeout = 200 * time.Millisecond
	authLib.BaseServiceGateway.ReadWriteTimeout = 200 * time.Millisecond
	return func(ctx *context.Context) {
		//token := ctx.Request.Header.Get("Authorization")
		token := ctx.Request.Header.Get("x-mmm-accesstoken")
		if len(token) > 0 {
			token = strings.TrimPrefix(token, "Bearer ")
			userToken := &domain.UserToken{}
			err := userToken.ParseToken(token)
			if err != nil {
				ctx.Output.SetStatus(http.StatusOK)
				ctx.Output.JSON(WithCodeMsgResponse(domain.InvalidRefreshToken), false, false)
				return
			}
			if userToken.UserId > 0 && userToken.CompanyId > 0 {
				loginCheckResponse, _ := authLib.LoginCheck(authlib.RequestLoginCheck{Token: token})
				if loginCheckResponse != nil && loginCheckResponse.Code == 901 {
					ctx.Output.SetStatus(http.StatusOK)
					ctx.Output.JSON(WithCodeMsgResponse(domain.InvalidRefreshToken), false, false)
					return
				}
			}
			ctx.Input.SetData("UserToken", userToken)
			ctx.Input.SetData("Accesstoken", token)
		}
	}
}

func WithCodeMsgResponse(code int) map[string]interface{} {
	msg := "token 过期或无效,需刷新令牌"
	if codeMsg, ok := domain.CodeMsg[code]; ok {
		msg = codeMsg
	}
	return map[string]interface{}{
		"msg":  msg,
		"code": code,
		"data": struct{}{},
	}
}

func RequestCostBefore() func(ctx *context.Context) {
	return func(ctx *context.Context) {
		ctx.Input.SetData("cost-begin", time.Now().UnixMilli())
	}
}

func RequestCostAfter(maxCost int64) func(ctx *context.Context) {
	return func(ctx *context.Context) {
		t := ctx.Input.GetData("cost-begin")
		if t != nil {
			costBegin := t.(int64)
			costEnd := time.Now().UnixMilli()
			cost := costEnd - costBegin
			if cost > 0 && maxCost > 0 && cost > maxCost {
				msg := fmt.Sprintf("beego | %v | %v | %v | 耗时:%v \n %v", ctx.Input.Method(), strings.Split(ctx.Request.RemoteAddr, ":")[0], ctx.Input.URL(), time.Duration(cost)*time.Millisecond, string(ctx.Input.RequestBody))
				logs.Warn(msg)
			}
		}
	}
}