package rbac

import (
	"github.com/gin-gonic/gin"

	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-portal/domain/adapter/account"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-portal/pkg/config"
	"github.com/tidbcloud/tidb-management-service/utilities/allowlist"
)

// If the request is rbac check it should set the following headers to the request:
// - Grpc-Metadata-X-Org-Id
// - Grpc-Metadata-X-User-Id
// - Grpc-Metadata--Project-Id-List
// - Grpc-Metadata-X-Default-Project-Id
// - Grpc-Metadata-X-Public-Key or Grpc-Metadata-X-User-Email
// - Grpc-Metadata-X-Debug-Trace-Id

const (
	grpcGatewayOrgIDKey             = "Grpc-Metadata-X-Org-Id"
	grpcGatewayUserIDKey            = "Grpc-Metadata-X-User-Id"
	grpcGatewayUserEmailKey         = "Grpc-Metadata-X-User-Email"
	grpcGatewayPublicKeyKey         = "Grpc-Metadata-X-Public-Key"
	grpcGatewayPublicKeyKeyId       = "Grpc-Metadata-X-Public-Key-Id"
	grpcGatewayAccessTokenKey       = "Grpc-Metadata-X-Access-Token"
	grpcGatewayDefaultProjectIDKey  = "Grpc-Metadata-X-Default-Project-Id"
	grpcGatewayProjectIDListKey     = "Grpc-Metadata-X-Project-Id-List"
	grpcGatewayClusterIDKey         = "Grpc-Metadata-X-Cluster-Id"
	grpcGatewayNoProjectRequiredKey = "Grpc-Metadata-X-No-Project-Required"

	// add grpc context metadata for auditlog
	// api key
	grpcGatewayXAuthType    = "Grpc-Metadata-X-Auth-Type"
	grpcGatewayXAuthContent = "Grpc-Metadata-X-Auth-Content"
	// access token
	grpcGatewayXAuthMethod = "Grpc-Metadata-X-Auth-Method"
	grpcGatewayXAuthRaw    = "Grpc-Metadata-X-Auth-Raw"
)

type Service interface {
	// CheckRBAC checks the RBAC permission via account service sdk.
	//   - It first calls account service to check whether user identity has permission to access the resource uri,
	//     which is registered manually by developers on account service.
	//   - Then it grabs the accessible project ids from multiple places and sets them to the request ctx.
	//   - The accessible project ids will pass to downstream services. They can parse the request body and do further permission check.
	CheckRBAC(ctx *gin.Context)
	// CheckAllowList checks the request permission against the 3-layer migration allowlist.
	CheckAllowList(ctx *gin.Context)
}

func NewRBACService(acc account.Client, allowList *allowlist.AllowLockList) Service {
	if config.Global().RBAC.LocalMode {
		return newFakeRBACService()
	}
	return newRBACService(acc, allowList)
}
