package middleware

import (
	"net/http"

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

	"chaitin.cn/patronus/safeline-2/management/webserver/api/response"
	"chaitin.cn/patronus/safeline-2/management/webserver/model"
	"chaitin.cn/patronus/safeline-2/management/webserver/pkg/constants"
	"chaitin.cn/patronus/safeline-2/management/webserver/pkg/database"
)

func AuthRequired(c *gin.Context) {
	session := sessions.Default(c)

	user := session.Get(constants.DefaultSessionUserKey)
	if user == nil {
		response.Error(c, response.ErrorLoginRequired, http.StatusUnauthorized)
		c.Abort()
		return
	}

	// Load user from database to get current role/status
	db := database.GetDB()
	var userModel model.User
	res := db.First(&userModel, user)
	if res.RowsAffected == 0 {
		response.Error(c, response.ErrorLoginRequired, http.StatusUnauthorized)
		c.Abort()
		return
	}

	// Check if user is still enabled
	if !userModel.IsEnabled {
		session.Clear()
		session.Save()
		response.Error(c, response.JSONBody{Err: "account_disabled", Msg: "Account has been disabled"}, http.StatusForbidden)
		c.Abort()
		return
	}

	// Store user info in context for downstream handlers
	c.Set("user_id", int(userModel.ID))
	c.Set("user_role", userModel.Role)
	c.Set("username", userModel.Username)

	// extend session expired time
	session.Options(sessions.Options{
		Path:   "/",
		MaxAge: 3600 * 24 * 7,
	})

	if err := session.Save(); err != nil {
		response.Error(c, response.JSONBody{Err: response.ErrInternalError, Msg: "Error occurred when creating sessions"}, http.StatusInternalServerError)
		return
	}

	c.Next()
}

// RequireRole returns a middleware that checks if the user has one of the required roles.
func RequireRole(roles ...string) gin.HandlerFunc {
	roleSet := make(map[string]bool)
	for _, r := range roles {
		roleSet[r] = true
	}
	return func(c *gin.Context) {
		userRole, exists := c.Get("user_role")
		if !exists {
			response.Error(c, response.ErrorLoginRequired, http.StatusUnauthorized)
			c.Abort()
			return
		}

		role, ok := userRole.(string)
		if !ok || !roleSet[role] {
			response.Error(c, response.JSONBody{Err: "forbidden", Msg: "Insufficient permissions"}, http.StatusForbidden)
			c.Abort()
			return
		}

		c.Next()
	}
}

func ReadOnly(c *gin.Context) {
	if c.Request.Method != "GET" && c.Request.Method != "HEAD" && c.Request.Method != "OPTIONS" {
		response.Error(c, response.ErrorReadOnly, http.StatusBadRequest)
		c.Abort()
	}
}
