package middleware

import (
	"bytes"
	"io"
	"strconv"
	"time"

	"kra/pkg/utils"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

// EmailSender 邮件发送接口
type EmailSender interface {
	ErrorToEmail(subject, body string) error
}

// UserFinder 用户查找接口
type UserFinder interface {
	FindUsernameByID(id int) (string, error)
}

// EmailConfig 邮件中间件配置
type EmailConfig struct {
	EmailSender EmailSender
	UserFinder  UserFinder
	Logger      *zap.Logger
}

// 全局邮件配置
var emailConfig *EmailConfig

// SetEmailConfig 设置邮件配置
func SetEmailConfig(cfg *EmailConfig) {
	emailConfig = cfg
}

// ErrorToEmail 错误发送邮件中间件（与 kra 保持一致）
func ErrorToEmail() gin.HandlerFunc {
	return func(c *gin.Context) {
		var username string

		// 获取用户信息
		claims, _ := utils.GetClaims(c)
		if claims != nil && claims.Username != "" {
			username = claims.Username
		} else {
			id, _ := strconv.Atoi(c.Request.Header.Get("x-user-id"))
			if id > 0 && emailConfig != nil && emailConfig.UserFinder != nil {
				if name, err := emailConfig.UserFinder.FindUsernameByID(id); err == nil {
					username = name
				} else {
					username = "Unknown"
				}
			} else {
				username = "Unknown"
			}
		}

		// 读取请求体
		body, _ := io.ReadAll(c.Request.Body)
		// 将原body塞回去
		c.Request.Body = io.NopCloser(bytes.NewBuffer(body))

		// 记录请求信息
		record := struct {
			IP     string
			Method string
			Path   string
			Agent  string
			Body   string
		}{
			IP:     c.ClientIP(),
			Method: c.Request.Method,
			Path:   c.Request.URL.Path,
			Agent:  c.Request.UserAgent(),
			Body:   string(body),
		}

		now := time.Now()

		c.Next()

		latency := time.Since(now)
		status := c.Writer.Status()
		errorMessage := c.Errors.ByType(gin.ErrorTypePrivate).String()

		// 构建邮件内容
		str := "接收到的请求为" + record.Body + "\n" +
			"请求方式为" + record.Method + "\n" +
			"报错信息如下" + errorMessage + "\n" +
			"耗时" + latency.String() + "\n"

		// 如果状态码不是200，发送邮件
		if status != 200 {
			subject := username + " " + record.IP + "调用了" + record.Path + "报错了"
			if emailConfig != nil && emailConfig.EmailSender != nil {
				if err := emailConfig.EmailSender.ErrorToEmail(subject, str); err != nil {
					if emailConfig.Logger != nil {
						emailConfig.Logger.Error("ErrorToEmail Failed, err:", zap.Error(err))
					}
				}
			}
		}
	}
}
