package middleware

import (
	"time"

	"mail_go/internal/store"

	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
)

const (
	// sessionAbsoluteMaxAge 会话绝对过期时间：超过后强制重新登录。
	sessionAbsoluteMaxAge = 7 * 24 * time.Hour
	// sessionSlidingRefresh 滑动续期阈值：距上次刷新超过该时长则更新
	// loginAt 并写回 cookie，保持活跃用户不中断（约 12 小时写回一次）。
	sessionSlidingRefresh = 12 * time.Hour
)

// sessionInt64 兼容不同底层 session store 解码出的整数类型。
func sessionInt64(v interface{}) (int64, bool) {
	switch n := v.(type) {
	case int64:
		return n, true
	case int:
		return int64(n), true
	case uint:
		return int64(n), true
	case uint64:
		return int64(n), true
	case float64:
		return int64(n), true
	default:
		return 0, false
	}
}

// AuthMiddleware checks for a valid session and loads the current user
// into the Gin context. If no valid session exists, it redirects to /login.
func AuthMiddleware(stores *store.Stores) gin.HandlerFunc {
	return func(c *gin.Context) {
		session := sessions.Default(c)
		userID := session.Get("userID")
		if userID == nil {
			c.Redirect(302, "/login")
			c.Abort()
			return
		}

		// 会话绝对过期：登录超过 7 天强制重新登录；
		// 滑动续期：活跃会话每 12 小时刷新一次 loginAt。
		if loginAt, ok := sessionInt64(session.Get("loginAt")); ok {
			elapsed := time.Since(time.Unix(loginAt, 0))
			if elapsed > sessionAbsoluteMaxAge {
				session.Clear()
				session.Save()
				c.Redirect(302, "/login")
				c.Abort()
				return
			}
			if elapsed > sessionSlidingRefresh {
				session.Set("loginAt", time.Now().Unix())
				session.Save()
			}
		}

		// userID is stored as uint in session, but sessions.Get returns interface{}
		// which may be stored as int or uint depending on the underlying store.
		var id uint
		switch v := userID.(type) {
		case uint:
			id = v
		case int:
			id = uint(v)
		case int64:
			id = uint(v)
		case float64:
			id = uint(v)
		default:
			session.Clear()
			session.Save()
			c.Redirect(302, "/login")
			c.Abort()
			return
		}

		user, err := stores.Users.GetByID(id)
		if err != nil {
			session.Clear()
			session.Save()
			c.Redirect(302, "/login")
			c.Abort()
			return
		}

		// 首次登录/密码被重置的用户必须先修改密码才能使用其他功能
		if user.MustChangePassword && c.Request.URL.Path != "/settings" && c.Request.URL.Path != "/logout" {
			c.Redirect(302, "/settings?force=1")
			c.Abort()
			return
		}

		c.Set("currentUser", user)
		c.Set("userID", id)
		c.Next()
	}
}
