package checker

import (
	"context"
	"regexp"
	"strconv"

	"github.com/samber/lo"
	"google.golang.org/grpc"

	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/pkg/apimiddleware/bizerror"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/grpc/metadata"
)

var organizationIDRegexp = regexp.MustCompile(`^\d+$`)

func NewOrganizationPermissionChecker(
	extractOrganizationID func(req any) (string, error),
) CheckFunc {
	return func(
		ctx context.Context,
		_ *CheckContext,
		req any,
		_ *grpc.UnaryServerInfo,
	) (context.Context, any, error) {
		reqMeta, err := metadata.ExtractRequestMeta(ctx)
		if err != nil {
			return ctx, req, bizerror.NewInternal(err, "failed to extract request metadata")
		}
		organizationIDString, err := extractOrganizationID(req)
		if err != nil {
			return ctx, req, err
		}
		if !organizationIDRegexp.MatchString(organizationIDString) {
			return ctx, req, bizerr.New(bizerr.ErrCodeParams, "invalid organization id %q", organizationIDString)
		}
		organizationID, err := strconv.ParseUint(organizationIDString, 10, 64)
		if err != nil {
			return ctx, req, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "invalid organization id")
		}
		if organizationID == 0 {
			return ctx, req, bizerr.New(bizerr.ErrCodeParams, "organization id must be greater than zero")
		}
		if organizationID != reqMeta.OrgID {
			return ctx, req, bizerr.New(bizerr.ErrCodePermission, "organization_id does not match authenticated organization")
		}
		reqMeta.IsCheckPermission = lo.ToPtr(true)
		return metadata.AppendToIncomingMeta(ctx, reqMeta), req, nil
	}
}
