package logs

import (
	log "app.yhyue.com/moapp/jylog"
	. "bp.jydev.jianyu360.cn/BaseService/gateway/common/gatecode"
	"bp.jydev.jianyu360.cn/BaseService/gateway/core/logs/internal/notice"
	"bp.jydev.jianyu360.cn/BaseService/gateway/core/logs/internal/savedb"
	"bp.jydev.jianyu360.cn/BaseService/gateway/core/router"
	"encoding/json"
	"fmt"
	"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"
	"strings"
	"time"
)

// server 请求日志
//type serverLog struct {
//	Notice internal.LogsNotice
//	SDb    internal.SaveLogsDb
//}

type serverLog struct {
	Notice *notice.Notice
	SDb    *savedb.DbLogs
}

func (s *serverLog) initNotice(nc *notice.Notice) *serverLog {
	s.Notice = nc
	return s
}

func (s *serverLog) initSaveLog(sDB *savedb.DbLogs) *serverLog {
	s.SDb = sDB
	go s.SDb.SaveLogTask()
	return s
}

// RecordLogAndNotice 记录请求日志及提醒
func (s *serverLog) RecordLogAndNotice(r *ghttp.Request, err error) {

	handlerCtx := router.GetGContext(r.GetCtx())

	//请求时间校验
	tookTime := gtime.TimestampMilli() - r.EnterTime
	if err == nil {
		compareTime := handlerCtx.RouterRule.TimeOut
		if compareTime == 0 {
			compareTime = 2000
		}
		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 err != nil {
		// 发送提醒信息
		if code.Code() > 2000 && s.Notice != nil {
			_ = s.Notice.SendWarnMsg(map[string]interface{}{
				"log": contextDetail,
			})
		}
		log.WithContext(r.Context()).Debugln(gerror.Stack(err))
	}

	if s.SDb != nil {
		s.SDb.AddLogToTask(PaseReq(handlerCtx, r))
	}
	//日志输出
	log.WithContext(r.Context()).Info(contextDetail)
}

func PaseReq(ctx *router.GContext, r *ghttp.Request) map[string]interface{} {
	md, _ := json.Marshal(r.Request.Form)
	m := map[string]interface{}{
		"ip":        r.GetClientIp(),
		"refer":     r.Referer(),
		"mdescribe": string(md),
		"client":    r.UserAgent(),
		"os":        getOS(r.UserAgent()),
		"browse":    getBrowse(r.UserAgent()),
		"method":    r.Method,
		"url":       r.URL.String(),
	}
	if ctx.Sess != nil {
		if ctx.Sess.UserId != "" {
			m["userid"] = ctx.Sess.UserId
		}
		if ctx.Sess.NewUid != 0 {
			m["userid_new"] = ctx.Sess.NewUid
		}
		if ctx.Sess.EntId != 0 {
			m["userid"] = ctx.Sess.EntId
		}
	}

	timeNow := time.Now()
	m["date"] = timeNow.Unix()
	m["year"] = timeNow.Year()
	m["month"] = timeNow.Month()
	m["day"] = timeNow.Day()
	m["hour"] = timeNow.Hour()
	m["minutes"] = timeNow.Minute()
	return m
}

// getOS 获取平台类型
func getOS(useros string) string {
	osVersion := "其他"
	if strings.Contains(useros, "NT 6.0") {
		osVersion = "Windows Vista/Server 2008"
	} else if strings.Contains(useros, "NT 5.2") {
		osVersion = "Windows Server 2003"
	} else if strings.Contains(useros, "NT 5.1") {
		osVersion = "Windows XP"
	} else if strings.Contains(useros, "NT 5") {
		osVersion = "Windows 2000"
	} else if strings.Contains(useros, "Mac") {
		osVersion = "Mac"
	} else if strings.Contains(useros, "Unix") {
		osVersion = "UNIX"
	} else if strings.Contains(useros, "Linux") {
		osVersion = "Linux"
	} else if strings.Contains(useros, "SunOS") {
		osVersion = "SunOS"
	} else if strings.Contains(useros, "NT 6.3") {
		osVersion = "Window8"
	} else if strings.Contains(useros, "NT 6.1") {
		osVersion = "Window7"
	} else if strings.Contains(useros, "NT 10.0") {
		osVersion = "Window10"
	}
	return osVersion
}

// getBrowse 获取浏览器类型
func getBrowse(userbrowser string) string {
	browserVersion := "其他"
	if strings.Contains(userbrowser, "MSIE") {
		browserVersion = "IE"
	} else if strings.Contains(userbrowser, "Firefox") {
		browserVersion = "Firefox"
	} else if strings.Contains(userbrowser, "Chrome") {
		browserVersion = "Chrome"
	} else if strings.Contains(userbrowser, "Safari") {
		browserVersion = "Safari"
	} else if strings.Contains(userbrowser, "rv:11.0") {
		browserVersion = "IE11"
	}
	return browserVersion
}
