package grpcli

import (
	"context"
	"fmt"
	"sync"

	"github.com/tidbcloud/account/idl/pbgen/proto/account"
	"github.com/tidbcloud/metrics-server/central/config"
	"github.com/tidbcloud/pkgv2/bizerr"
	tigrpc "github.com/tidbcloud/tiinf/transport/tigrpc/client"
)

var (
	accountProviderSvcOnce sync.Once
	accountProviderSvcCli  account.AccountAPIServiceClient
)

func getAccountSvcClient() account.AccountAPIServiceClient {

	accountProviderSvcOnce.Do(func() {
		conn, err := tigrpc.NewClientConn(config.Global().GrpcConfig.AccountProviderSvcAddr, tigrpc.WithDefault())
		if err != nil {
			panic(fmt.Sprintf("dial account-provider-svc: %s", err))
		}

		accountProviderSvcCli = account.NewAccountAPIServiceClient(conn)
	})
	return accountProviderSvcCli
}

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 resp.BaseResp.ErrCode != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(resp.BaseResp.ErrCode), 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 resp.BaseResp.ErrCode != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(resp.BaseResp.ErrCode), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

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 resp.BaseResp.ErrCode != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(resp.BaseResp.ErrCode), 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 resp.BaseResp.ErrCode != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(resp.BaseResp.ErrCode), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func ListProjectsByOrgsInUser(ctx context.Context, req *account.ListProjectsByOrgsInUserRequest) (*account.ListProjectsByOrgsInUserResponse, bizerr.BizError) {
	client := getAccountSvcClient()

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

func ListOrgsByUser(ctx context.Context, req *account.ListOrgsByUserRequest) (*account.ListOrgsByUserResponse, bizerr.BizError) {
	client := getAccountSvcClient()

	resp, err := client.ListOrgsByUser(ctx, req)
	if err != nil {
		return resp, bizerr.WrapGrpcError(err, "ListOrgsByUser")
	}
	if resp.BaseResp.ErrCode != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(resp.BaseResp.ErrCode), 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 resp.BaseResp.ErrCode != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(resp.BaseResp.ErrCode), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func SendEmail(ctx context.Context, req *account.SendEmailReq) (*account.SendEmailResp, bizerr.BizError) {
	client := getAccountSvcClient()

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