package auth

import (
	"net/http"

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

const ctxSessionKey = "km_session"

func GetSessionFromContext(c *gin.Context) *Session {
	v, _ := c.Get(ctxSessionKey)
	sess, _ := v.(*Session)
	return sess
}

func InstanceID(c *gin.Context) string {
	if s := GetSessionFromContext(c); s != nil {
		return s.InstanceID
	}
	return ""
}

func Role(c *gin.Context) string {
	if s := GetSessionFromContext(c); s != nil {
		return s.Role
	}
	return ""
}

func UserID(c *gin.Context) string {
	if s := GetSessionFromContext(c); s != nil {
		return s.UserID
	}
	return ""
}

func RequireRole(roles ...string) gin.HandlerFunc {
	return func(c *gin.Context) {
		r := Role(c)
		for _, want := range roles {
			if r == want {
				c.Next()
				return
			}
		}
		c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "insufficient role"})
	}
}

func Middleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		cookie, err := c.Request.Cookie(sessionCookieName)
		if err != nil {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "not authenticated"})
			return
		}

		sess, err := GetSession(c.Request.Context(), cookie.Value)
		if err != nil {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "session expired"})
			return
		}

		if sess.InstanceID == "" {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "session has no organization"})
			return
		}

		c.Set(ctxSessionKey, sess)

		if hostInstance, ok := InstanceFromHost(c); ok && hostInstance.InstanceID != sess.InstanceID {
			c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "instance host mismatch"})
			return
		}

		c.Next()
	}
}
