package testkit

import (
	"net/http"

	"github.com/gin-gonic/gin"

	"github.com/tidbcloud/AgentTeam/internal/store/identity"
	"github.com/tidbcloud/AgentTeam/internal/store/workspace"
)

const (
	ctxKeyAuthenticatedUser = "testkit.authenticated_user"
	ctxKeyCurrentWorkspace  = "testkit.current_workspace"
)

func RequireAuthenticatedUser(runtime *Runtime) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		token, ok := BearerTokenFromRequest(ctx)
		if !ok {
			WriteAPIError(ctx, http.StatusUnauthorized, "Missing bearer token")
			ctx.Abort()
			return
		}
		authenticated, err := runtime.Store.Identity().AuthenticateSession(ctx.Request.Context(), token)
		if err != nil {
			WriteAPIError(ctx, http.StatusUnauthorized, "Invalid access token")
			ctx.Abort()
			return
		}
		ctx.Set(ctxKeyAuthenticatedUser, authenticated)
		ctx.Next()
	}
}

func RequireCurrentWorkspace(runtime *Runtime) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		workspaceID, ok := WorkspaceIDFromRequest(ctx)
		if !ok {
			WriteAPIError(ctx, http.StatusBadRequest, "No workspace selected")
			ctx.Abort()
			return
		}

		authenticated, ok := AuthenticatedUserFromContext(ctx)
		if !ok {
			WriteAPIError(ctx, http.StatusUnauthorized, "Unauthorized")
			ctx.Abort()
			return
		}

		workspaceSummary, err := runtime.Store.GetWorkspaceForUser(ctx.Request.Context(), authenticated.User.ID, workspaceID)
		if err != nil {
			WriteAPIError(ctx, http.StatusForbidden, "Forbidden")
			ctx.Abort()
			return
		}
		ctx.Set(ctxKeyCurrentWorkspace, workspaceSummary)
		ctx.Next()
	}
}

func RequireVerifiedIdentity(runtime *Runtime) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		authenticated, ok := AuthenticatedUserFromContext(ctx)
		if !ok {
			WriteAPIError(ctx, http.StatusUnauthorized, "Unauthorized")
			ctx.Abort()
			return
		}

		if !runtime.EmailVerificationRequired || authenticated.User.HasVerifiedIdentity() {
			ctx.Next()
			return
		}

		ctx.JSON(http.StatusForbidden, gin.H{
			"error": "Email or mobile not verified",
			"code":  ErrorCodeEmailNotVerified,
		})
		ctx.Abort()
	}
}

func RequireSystemAdmin() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		authenticated, ok := AuthenticatedUserFromContext(ctx)
		if !ok {
			WriteAPIError(ctx, http.StatusUnauthorized, "Unauthorized")
			ctx.Abort()
			return
		}
		if !authenticated.User.IsAdmin {
			WriteAPIError(ctx, http.StatusForbidden, "Forbidden")
			ctx.Abort()
			return
		}
		ctx.Next()
	}
}

func AuthenticatedUserFromContext(ctx *gin.Context) (identity.AuthenticatedUser, bool) {
	value, ok := ctx.Get(ctxKeyAuthenticatedUser)
	if !ok {
		return identity.AuthenticatedUser{}, false
	}
	authenticated, ok := value.(identity.AuthenticatedUser)
	if !ok {
		return identity.AuthenticatedUser{}, false
	}
	return authenticated, true
}

func CurrentWorkspaceFromContext(ctx *gin.Context) (workspace.Summary, bool) {
	value, ok := ctx.Get(ctxKeyCurrentWorkspace)
	if !ok {
		return workspace.Summary{}, false
	}
	workspaceSummary, ok := value.(workspace.Summary)
	if !ok {
		return workspace.Summary{}, false
	}
	return workspaceSummary, true
}
