package middleware

import (
	"context"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/nexuscrm/kernel/pkg/auth"
	"github.com/nexuscrm/permissions"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/pingcap-inc/nexuscrm-api-host/hostruntime"
	apihostmiddleware "github.com/pingcap-inc/nexuscrm-api-host/middleware"
)

func (backendSessionContextWriter) ReadSession(c *gin.Context) apihostmiddleware.SessionLookup {
	if c == nil {
		return apihostmiddleware.SessionLookup{}
	}
	userInterface, exists := c.Get(constants.ContextKeyUser)
	if !exists {
		return apihostmiddleware.SessionLookup{}
	}
	authUser, ok := userInterface.(auth.UserSession)
	if !ok {
		return apihostmiddleware.SessionLookup{Exists: true}
	}
	return apihostmiddleware.SessionLookup{
		User:   hostUserSessionFromAuth(authUser),
		Exists: true,
		Valid:  true,
	}
}

func (backendSessionContextWriter) WriteCurrentSession(c *gin.Context, user hostruntime.UserSession) {
	if c == nil {
		return
	}
	c.Set(constants.ContextKeyUser, authUserSessionFromHost(user))
}

func (backendSessionContextWriter) WritePermissions(c *gin.Context, systemPerms, customPerms map[string]bool) {
	if c == nil {
		return
	}
	c.Set(constants.ContextKeySystemPermissions, systemPerms)
	c.Set(constants.ContextKeyCustomPermissions, customPerms)
	if c.Request != nil {
		ctx := c.Request.Context()
		ctx = context.WithValue(ctx, constants.ContextKeySystemPermissions, systemPerms)
		ctx = context.WithValue(ctx, constants.ContextKeyCustomPermissions, customPerms)
		if userInterface, exists := c.Get(constants.ContextKeyUser); exists {
			if authUser, ok := userInterface.(auth.UserSession); ok {
				ctx = permissions.WithEffectivePermissions(ctx, authUser.ID, authUser.ProfileId, systemPerms, customPerms)
			}
		}
		c.Request = c.Request.WithContext(ctx)
	}
}

func (backendSessionContextWriter) SystemPermissions(c *gin.Context) apihostmiddleware.PermissionLookup {
	if c == nil {
		return apihostmiddleware.PermissionLookup{}
	}
	permsInterface, exists := c.Get(constants.ContextKeySystemPermissions)
	if !exists {
		return apihostmiddleware.PermissionLookup{}
	}
	perms, ok := permsInterface.(map[string]bool)
	return apihostmiddleware.PermissionLookup{
		Permissions: perms,
		Exists:      true,
		Valid:       ok,
	}
}

func (backendSessionContextWriter) RequestID(c *gin.Context) string {
	return GetRequestID(c)
}

func (backendSessionContextWriter) WriteConnectedAppID(c *gin.Context, connectedAppID string) {
	if c == nil {
		return
	}
	connectedAppID = apihostmiddleware.CanonicalConnectedAppID(connectedAppID)
	if connectedAppID == "" {
		return
	}
	c.Set(ContextKeyConnectedAppID, connectedAppID)
	c.Request = c.Request.WithContext(ContextWithConnectedAppID(c.Request.Context(), connectedAppID))
}

func hostUserSessionFromAuth(user auth.UserSession) hostruntime.UserSession {
	return hostruntime.UserSession{
		ID:                user.ID,
		Name:              user.Name,
		Email:             user.Email,
		ProfileID:         user.ProfileId,
		ProfileName:       user.ProfileName,
		RoleID:            user.RoleId,
		RoleName:          user.RoleName,
		ConnectedAppID:    strings.TrimSpace(user.ConnectedAppId),
		Scope:             user.Scope,
		GrantType:         user.GrantType,
		SessionClass:      user.SessionClass,
		SystemPermissions: user.SystemPermissions,
	}
}
