package logs

import (
	"fmt"
	. "gateway/common/gatecode"
	"gateway/core/proxy/router"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/text/gstr"
)

// RecordLogAndNotice 记录请求日志及提醒
func (s *serverLog) RecordLogAndNotice(r *ghttp.Request, err error) {
	if !s.Config.ServerAccessLogEnabled && //关闭成功日志
		!s.Config.ServerErrorLogEnabled && //关闭错误日志
		s.Notice == nil { //关闭消息通知
		return
	}
	handlerCtx := router.GetGContext(r.GetCtx())

	//请求时间校验
	tookTime := gtime.TimestampMilli() - r.EnterTime
	if err == nil {
		compareTime := handlerCtx.RouterRule.TimeOut
		if compareTime == 0 {
			compareTime = s.Config.ServerRequestTimeout
		}
		if tookTime > compareTime {
			err = NewErrorWithCode(SERVER_DETAIL_TIMEOUT, fmt.Sprintf("接口超时: %d>%d", handlerCtx.RouterRule.TimeOut, tookTime))
		}
	}

	var (
		scheme        = "http"
		proto         = r.Header.Get("X-Forwarded-Proto")
		code          = gerror.Code(err)
		codeDetail    = code.Detail()
		codeDetailStr string
	)
	if r.TLS != nil || gstr.Equal(proto, "https") {
		scheme = "https"
	}

	if codeDetail != nil { //存在错误信息
		codeDetailStr = gstr.Replace(fmt.Sprintf(`%+v`, codeDetail), "\n", " ")
	} else if err != nil {
		codeDetailStr = err.Error()
	}

	contextDetail := fmt.Sprintf(
		`%d %s "%s://%s%s proxy:%s  %s" %d ms, %s, "%s", "%s", %d, "%s", "%+v"`,
		r.Response.Status, r.Method, scheme, r.Host, r.URL.String(), handlerCtx.ServerAddr, r.Proto,
		tookTime, r.GetClientIp(), r.Referer(), r.UserAgent(),
		code.Code(), code.Message(), codeDetailStr,
	)

	// 发送提醒信息
	if s.Notice != nil {
		_ = s.Notice.SendWarnMsg(map[string]interface{}{
			"log": contextDetail,
		})
	}

	if err != nil && s.Config.ServerErrorStack {
		if stack := gerror.Stack(err); stack != "" {
			contextDetail += "\nStack:\n" + stack
		} else {
			contextDetail += ", " + err.Error()
		}
	}

	if err == nil && s.Config.ServerAccessLogEnabled { //记录成功
		s.accessLog.Printf(r.Context(), contextDetail)
	} else if err != nil && s.Config.ServerErrorLogEnabled { //记录异常日志
		s.errorLog.Printf(r.Context(), contextDetail)
	}
}
