package acl

import (
	"context"
	"sync"

	"github.com/tidbcloud/ecosystem-service/config"
	"github.com/tidbcloud/ecosystem-service/internal/service/grpc/acl/client"
	"github.com/tidbcloud/ecosystem-service/internal/utils"
	"github.com/tidbcloud/pkgv2/bizerr"
	"github.com/tidbcloud/pkgv2/tracing"
	"go.opentelemetry.io/otel"

	"github.com/tidbcloud/account/idl/pbgen/proto/acl"
)

var Tracer = otel.Tracer("grpc-acl")

type AclSvc interface {
	GetOpenAPIAccess(ctx context.Context, req *acl.GetOpenAPIAccessReq) (*acl.GetOpenAPIAccessResp, error)
	GetJwtByUser(ctx context.Context, clusterId uint64, userId uint64, email string) (string, string, error)
}

type aclSvcImpl struct {
	client acl.AccessServiceClient
}

var (
	aclSvc     *aclSvcImpl
	aclSvcOnce sync.Once
)

func NewAclSvc(conf *config.ConfigWrapper) AclSvc {
	aclSvcOnce.Do(func() {
		aclSvc = &aclSvcImpl{
			client: client.GetAclSvcClient(conf),
		}
	})
	return aclSvc
}

func (svc *aclSvcImpl) GetOpenAPIAccess(ctx context.Context, req *acl.GetOpenAPIAccessReq) (_ *acl.GetOpenAPIAccessResp, err error) {
	ctx, span := Tracer.Start(ctx, "aclSvcImpl.GetOpenAPIAccess")
	defer func() {
		tracing.EndSpan(span, err)
	}()

	resp, err := svc.client.GetOpenAPIAccess(ctx, req)
	if err != nil {
		return nil, utils.WrapGrpcError(err)
	}
	return resp, nil
}

func (svc *aclSvcImpl) GetJwtByUser(ctx context.Context, clusterId uint64, userId uint64, email string) (dbuser, jwt string, err error) {
	ctx, span := Tracer.Start(ctx, "aclSvcImpl.GetJwtByUser")
	defer func() {
		tracing.EndSpan(span, err)
	}()

	req := &acl.GetJwtByUserReq{
		ClusterId: clusterId,
		UserId:    userId,
		Email:     email,
	}
	resp, err := svc.client.GetJwtByUser(ctx, req)
	if err != nil {
		return "", "", utils.WrapGrpcError(err)
	}
	if resp.BaseResp.ErrCode != 0 {
		return "", "", bizerr.Restore(bizerr.ErrCode(resp.BaseResp.ErrCode), resp.BaseResp.ErrMsg)
	}
	return resp.DbUser, resp.Jwt, nil
}
