package middleware

import (
	"ALLinSSL/backend/public"
	"crypto/md5"
	"encoding/gob"
	"encoding/hex"
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	"net/http"
	"strconv"
	"strings"
	"time"
)

var Html404 = []byte(`<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>AllinSSL</center>
</body>
</html>`)

func SessionAuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		if checkApiKey(c) {
			return
		}

		routePath := c.Request.URL.Path
		method := c.Request.Method
		paths := strings.Split(strings.TrimPrefix(routePath, "/"), "/")
		session := sessions.Default(c)
		now := time.Now()
		gob.Register(time.Time{})
		if public.Secure == "/" || public.Secure == "/login" {
			// 如果安全入口是根目录或登录页，则不需要特殊处理
			public.Secure = ""
		}
		if public.Secure == "" && session.Get("secure") == nil {
			session.Set("secure", true)
			session.Set("lastRequestTime", now)
			session.Save()
		}
		last := session.Get("lastRequestTime")

		if routePath == public.Secure {
			if session.Get("secure") == nil {
				// 访问安全入口，设置 session
				session.Set("secure", true)
				session.Set("lastRequestTime", now)
				// 一定要保存 session BEFORE redirect
				session.Save()
			}
			// 返回登录页
			c.Redirect(http.StatusFound, "/login")
			c.Abort()
			return
		} else {
			if session.Get("secure") == nil || last == nil {
				c.Data(404, "text/html; charset=utf-8", Html404)
				c.Abort()
				return
			} else {
				if lastTime, ok := last.(time.Time); ok {
					if now.Sub(lastTime) >= time.Second*time.Duration(public.TimeOut) {
						if session.Get("login") == nil {
							session.Clear()
							session.Save()
							c.Data(404, "text/html; charset=utf-8", Html404)
							c.Abort()
							return
						} else {
							session.Delete("login")
							session.Set("lastRequestTime", now)
							session.Save()
							c.Redirect(http.StatusFound, "/login")
							return
						}
					} else {
						if session.Get("login") == nil {
							if len(paths) > 0 {
								if paths[0] == "login" {
									c.Next()
									return
								}
							}
							if len(paths) > 1 {
								if paths[1] == "login" {
									c.Next()
									return
								}
							}
							if routePath == "/favicon.ico" {
								return
							}
							// 判断是否为静态文件路径
							if method == "GET" {
								if len(paths) > 1 && paths[0] == "static" {
									c.Next()
									return
								}
							}
							// 返回登录页
							c.Redirect(http.StatusFound, "/login")
							c.Abort()
							return
						} else {
							if session.Get("__login_key") != public.LoginKey {
								// session.Set("secure", true)
								session.Set("login", nil)
								session.Save()
								// c.JSON(http.StatusUnauthorized, gin.H{"message": "登录信息发生变化，请重新登录"})
								c.Redirect(http.StatusFound, "/login")
								c.Abort()
							} else {
								// 访问正常，更新最后请求时间
								session.Set("lastRequestTime", now)
								session.Save()
								if paths[0] == "login" {
									c.Redirect(http.StatusFound, "/")
									c.Abort()
									return
								}
							}
						}
					}
				} else {
					c.Data(404, "text/html; charset=utf-8", Html404)
					c.Abort()
					return
				}
			}
		}
	}
}

func checkApiKey(c *gin.Context) bool {
	var form struct {
		ApiToken  string `form:"api_token"`
		Timestamp string `form:"timestamp"`
	}
	err := c.Bind(&form)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
		c.Abort()
		return false
	}
	if form.ApiToken == "" || form.Timestamp == "" {
		return false
	}
	apiKey := public.GetSettingIgnoreError("api_key")
	if apiKey == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "未开启api"})
		c.Abort()
		return false
	}
	// timestamp := time.Now().Unix()
	ApiToken := generateSignature(form.Timestamp, apiKey)
	if form.ApiToken != ApiToken {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token"})
		c.Abort()
		return false
	}
	// 这里可以添加其他的验证逻辑，比如检查时间戳是否过期等
	timestamp, err := strconv.ParseInt(form.Timestamp, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid timestamp"})
		return false
	}
	if time.Now().Unix()-timestamp > 60*5 {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "timestamp expired"})
		return false
	}
	return true
}

func generateSignature(timestamp, apiKey string) string {
	keyMd5 := md5.Sum([]byte(apiKey))
	keyMd5Hex := strings.ToLower(hex.EncodeToString(keyMd5[:]))

	signMd5 := md5.Sum([]byte(timestamp + keyMd5Hex))
	signMd5Hex := strings.ToLower(hex.EncodeToString(signMd5[:]))
	return signMd5Hex
}
