package grpcli

import (
	"context"
	"sync"

	"github.com/tidbcloud/account/idl/pbgen/proto/account"
	"github.com/tidbcloud/dataflow-service/internal/config"
	"github.com/tidbcloud/dataflow-service/pkg/grpc/grpcli"
	"github.com/tidbcloud/pkgv2/bizerr"
)

var (
	accountCli     account.AccountAPIServiceClient
	accountSvcOnce sync.Once
)

type AccountAPIHandlerImpl struct{}

func getAccountSvcClient() account.AccountAPIServiceClient {
	accountSvcOnce.Do(func() {
		ctx := context.Background()
		addr := config.Global().GrpcConfig.AccountProviderAddr
		conn := grpcli.MustBuildGrpcClientConnection(ctx, addr)
		accountCli = account.NewAccountAPIServiceClient(conn)
	})
	return accountCli
}

func GetUserByID(ctx context.Context, req *account.GetUserByIDRequest) (*account.GetUserByIDResponse, bizerr.BizError) {
	client := getAccountSvcClient()

	resp, err := client.GetUserByID(ctx, req)
	if err != nil {
		return resp, bizerr.WrapGrpcError(err, "GetUserByID")
	}
	if code := resp.BaseResp.ErrCode; code != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(code), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func GetUserByEmail(ctx context.Context, req *account.GetUserByEmailRequest) (*account.GetUserByEmailResponse, bizerr.BizError) {
	client := getAccountSvcClient()

	resp, err := client.GetUserByEmail(ctx, req)
	if err != nil {
		return resp, bizerr.WrapGrpcError(err, "GetUserByEmail")
	}
	if code := resp.BaseResp.ErrCode; code != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(code), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func GetAuthUser(ctx context.Context, req *account.GetAuthUserRequest) (*account.GetAuthUserResponse, bizerr.BizError) {
	client := getAccountSvcClient()

	resp, err := client.GetAuthUser(ctx, req)
	if err != nil {
		return resp, bizerr.WrapGrpcError(err, "GetAuthUser")
	}
	if code := resp.BaseResp.ErrCode; code != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(code), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func GetOrCreateSystemUser(ctx context.Context, req *account.GetOrCreateSystemUserRequest) (*account.GetOrCreateSystemUserResponse, bizerr.BizError) {
	client := getAccountSvcClient()

	resp, err := client.GetOrCreateSystemUser(ctx, req)
	if err != nil {
		return resp, bizerr.WrapGrpcError(err, "GetOrCreateSystemUser")
	}
	if code := resp.BaseResp.ErrCode; code != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(code), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func GetOrgByID(ctx context.Context, req *account.GetOrgByIDRequest) (*account.GetOrgByIDResponse, bizerr.BizError) {
	client := getAccountSvcClient()

	resp, err := client.GetOrgByID(ctx, req)
	if err != nil {
		return resp, bizerr.WrapGrpcError(err, "GetOrgByID")
	}
	if code := resp.BaseResp.ErrCode; code != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(code), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func ListOrgs(ctx context.Context, req *account.OrgFilter) (*account.ListOrgsResponse, bizerr.BizError) {
	client := getAccountSvcClient()

	resp, err := client.ListOrgs(ctx, req)
	if err != nil {
		return resp, bizerr.WrapGrpcError(err, "ListOrgs")
	}
	if code := resp.BaseResp.ErrCode; code != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(code), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func CreateAuditLog(ctx context.Context, req *account.CreateAuditLogRequest) (*account.CreateAuditLogResponse, bizerr.BizError) {
	client := getAccountSvcClient()

	resp, err := client.CreateAuditLog(ctx, req)
	if err != nil {
		return resp, bizerr.WrapGrpcError(err, "CreateAuditLog")
	}
	if code := resp.BaseResp.ErrCode; code != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(code), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func ListProjects(ctx context.Context, req *account.ProjectFilter) (*account.ListProjectsResponse, bizerr.BizError) {
	client := getAccountSvcClient()

	resp, err := client.ListProjects(ctx, req)
	if err != nil {
		return resp, bizerr.WrapGrpcError(err, "ListProjects")
	}
	if code := resp.BaseResp.ErrCode; code != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(code), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func GetProjectByID(ctx context.Context, req *account.GetProjectByIDRequest) (*account.GetProjectByIDResponse, bizerr.BizError) {
	client := getAccountSvcClient()

	resp, err := client.GetProjectByID(ctx, req)
	if err != nil {
		return resp, bizerr.WrapGrpcError(err, "GetProjectByID")
	}
	if code := resp.BaseResp.ErrCode; code != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(code), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func ListTrials(ctx context.Context, req *account.TrialFilter) (*account.ListTrialsResponse, bizerr.BizError) {
	client := getAccountSvcClient()

	resp, err := client.ListTrials(ctx, req)
	if err != nil {
		return resp, bizerr.WrapGrpcError(err, "ListTrial")
	}
	if code := resp.BaseResp.ErrCode; code != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(code), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}
