package midware

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"reflect"
	"runtime"
	"strings"
	"time"

	"be.ems/lib/core/utils/parse"
	"be.ems/lib/dborm"
	"be.ems/src/framework/constants/common"
	"be.ems/src/framework/middleware/collectlogs"
	"be.ems/src/framework/utils/ip2region"
	"be.ems/src/modules/system/model"
	"be.ems/src/modules/system/service"
)

// 敏感属性字段进行掩码
var maskProperties []string = []string{
	"password",
	"oldPassword",
	"newPassword",
	"confirmPassword",
}

// LogOperate 操作日志搜集
func LogOperate(options collectlogs.Options) func(http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			startTime := time.Now()

			// 只对前端发送的数据进行记录
			appCodeStr := r.Header.Get("X-App-Code")
			if appCodeStr == "" {
				next.ServeHTTP(w, r)
				return
			}

			// 函数名
			funcName := runtime.FuncForPC(reflect.ValueOf(next).Pointer()).Name()
			lastDotIndex := strings.LastIndex(funcName, "/")
			funcName = funcName[lastDotIndex+1:]

			// 用户名
			username := "-"
			accessToken := r.Header.Get("AccessToken")
			if accessToken != "" {
				// 验证令牌 == 这里直接查数据库session
				se, _ := dborm.XormUpdateSessionShakeTime(accessToken)
				username = se.AccountId
			}

			// 解析ip地址
			ip := strings.Split(r.RemoteAddr, ":")[0]
			ipaddr := ip2region.ClientIP(ip)
			location := ip2region.RealAddressByIp(ipaddr)
			// 操作日志记录
			operLog := model.SysLogOperate{
				Title:         options.Title,
				BusinessType:  options.BusinessType,
				OperatorType:  collectlogs.OPERATOR_TYPE_MANAGE,
				Method:        funcName,
				OperURL:       r.RequestURI,
				RequestMethod: r.Method,
				OperIP:        ipaddr,
				OperLocation:  location,
				OperName:      username,
				DeptName:      "",
			}

			// 是否需要保存request，参数和值
			if options.IsSaveRequestData && (r.Method == "POST" || r.Method == "PUT") {
				// 读取请求体内容
				body, err := io.ReadAll(r.Body)
				if err != nil {
					http.Error(w, "Internal Server Error", http.StatusInternalServerError)
					return
				}
				// 解析json内参数
				var bodyArgs map[string]any
				_ = json.Unmarshal(bytes.Clone(body), &bodyArgs)
				// 将请求体内容存储在临时缓冲区中
				buffer := bytes.NewBuffer(body)
				r.Body = io.NopCloser(buffer)

				params := bodyArgs
				for k, v := range params {
					// 敏感属性字段进行掩码
					for _, s := range maskProperties {
						if s == k {
							params[k] = parse.SafeContent(v.(string))
							break
						}
					}
				}
				jsonStr, _ := json.Marshal(params)
				paramsStr := string(jsonStr)
				if len(paramsStr) > 2000 {
					paramsStr = paramsStr[:2000]
				}
				operLog.OperParam = paramsStr
			}

			next.ServeHTTP(w, r)

			// 响应内容长度和状态码作为结果
			str := strings.TrimSuffix(fmt.Sprintf("%v", w), "}")
			strArr := strings.Split(str, " ")
			size := strArr[1]
			status := strArr[2]

			// 响应状态
			if status == "200" || status == "204" {
				operLog.Status = common.STATUS_YES
			} else {
				operLog.Status = common.STATUS_NO
			}

			// 是否需要保存response，参数和值
			if options.IsSaveResponseData {
				contentDisposition := w.Header().Get("Content-Disposition")
				contentType := w.Header().Get("Content-Type")
				content := contentType + contentDisposition
				msg := fmt.Sprintf(`{"status":"%s","size":"%s","content-type":"%s"}`, status, size, content)
				operLog.OperMsg = msg
			}

			// 日志记录时间
			duration := time.Since(startTime)
			operLog.CostTime = duration.Milliseconds()
			operLog.OperTime = time.Now().UnixMilli()

			// 保存操作记录到数据库
			service.NewSysLogOperateImpl.InsertSysLogOperate(operLog)

		})
	}
}
