package controller

import (
	"enterprise/common/config"
	"enterprise/common/dao"
	"enterprise/common/model"
	"enterprise/server/session"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gogap/errors"
	log "github.com/sirupsen/logrus"
	"github.com/smbrave/goutil"
	"net/http"
	"runtime"
	"time"
)

type Response struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data"`
}

type Base struct {
}

// 所有请求都必须走的逻辑,用于创建session
func (c *Base) Before(ctx *gin.Context) {
	if ctx.Keys == nil {
		ctx.Keys = make(map[string]interface{})
	}

	// 获取头部参数
	var header session.AdminHeader
	if err := ctx.BindHeader(&header); err != nil {
		panic(config.ErrParam.New().Append(err))
	}

	if header.Token == "" { // 新用户没有extra所以extra中的配置不能对新用户生效
		ctx.Keys[session.ContextSession] = session.NewAdminSession(&header, nil)
		return
	}

	var tk *model.StaffToken = nil

	tk, err := dao.NewStaffTokenDao().GetByToken(header.Token)
	if err != nil {
		panic(config.ErrDb.New().Append(err))
	}

	if tk == nil {
		panic(config.ErrTokenInvaild.New())
	}
	if time.Now().Unix() > tk.ExpireTime {
		panic(config.ErrTokenExpire.New())
	}
	staffUser, err := dao.NewStaffUserDao().Get(tk.UserId)
	if err != nil {
		panic(config.ErrDb.New().Append(err))
	}
	if staffUser == nil {
		panic(config.ErrTokenInvaild.New())
	}

	ctx.Keys[session.ContextSession] = session.NewAdminSession(&header, staffUser)
}

func (c *Base) Token(ctx *gin.Context) {
	// 只有需要传token的接口需要强制校验token
	sess := ctx.Keys[session.ContextSession].(*session.AdminSession)
	if sess.GetHeader().Token == "" {
		panic(config.ErrNoToken.New())
	}
}

func (c *Base) Recovery(ctx *gin.Context) {
	defer func() {
		if err := recover(); err != nil {
			var rsp Response
			if e, ok := err.(errors.ErrCode); ok {
				rsp.Code = int(e.Code())
				rsp.Message = e.Error()
				ctx.JSON(http.StatusOK, rsp)
				log.Errorf("[%s][%s][%s] %s", ctx.Request.Method, ctx.Request.URL.Path, ctx.Request.URL.RawQuery, e.Error())
			} else {
				var buf [2 << 10]byte
				stack := string(buf[:runtime.Stack(buf[:], true)])
				log.Errorf("[%s][%s][%s] Internal ERROR:::%v stack:%s", ctx.Request.Method, ctx.Request.URL.Path, ctx.Request.URL.RawQuery, err, stack)
				rsp.Code = -1
				rsp.Message = fmt.Sprintf("%v", err)
				ctx.JSON(http.StatusOK, rsp)
			}
			ctx.Abort()
		}
	}()
	start := time.Now()
	ctx.Next()

	log.Infof("[%s][%s] cost[%s] query[%s] params[%s]",
		ctx.Request.Method, ctx.Request.URL.Path, time.Since(start),
		ctx.Request.URL.RawQuery, goutil.EncodeJSON(ctx.Keys[config.ContextParam]))
}