package grpcli

import (
	"context"
	"fmt"
	"sync"

	"github.com/tidbcloud/account/idl/pbgen/proto/account"
	"github.com/tidbcloud/pkgv2/bizerr"
	"github.com/tidbcloud/pkgv2/log"
	"github.com/tidbcloud/serverless-service/internal/config"
	tigrpc "github.com/tidbcloud/tiinf/transport/tigrpc/client"
	"go.uber.org/zap"
)

var (
	accountSvcOnce sync.Once
	accountSvcCli  account.AccountAPIServiceClient
)

func getAccountSvcClient() account.AccountAPIServiceClient {
	accountSvcOnce.Do(func() {
		ctx := context.Background()
		addr := config.Global().SvcAddrConfig.AccountSvcAddr

		conn, err := tigrpc.NewClientConn(addr, tigrpc.WithDefault())
		log.Info(ctx, "Initializing account service client", zap.Any("err", err), zap.String("addr", addr))
		if err != nil {
			panic(fmt.Sprintf("dial account-svc: %s", err))
		}

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

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

	resp, err := client.GetUserByEmail(ctx, req)
	if err != nil {
		return nil, wrapGrpcError(err)
	}
	if err := parseBaseResp(resp.BaseResp); err != nil {
		return nil, err
	}
	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 nil, wrapGrpcError(err)
	}
	if err := parseBaseResp(resp.BaseResp); err != nil {
		return nil, err
	}
	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 nil, wrapGrpcError(err)
	}
	if err := parseBaseResp(resp.BaseResp); err != nil {
		return nil, err
	}
	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 nil, wrapGrpcError(err)
	}
	if err := parseBaseResp(resp.BaseResp); err != nil {
		return nil, err
	}
	return resp, nil
}

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

	resp, err := client.GetOrgByID(ctx, req)
	if err != nil {
		return nil, wrapGrpcError(err)
	}
	if err := parseBaseResp(resp.BaseResp); err != nil {
		return nil, err
	}
	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 nil, wrapGrpcError(err)
	}
	if err := parseBaseResp(resp.BaseResp); err != nil {
		return nil, err
	}
	return resp, nil
}

func ListOrgsAdvance(
	ctx context.Context,
	req *account.ListOrgsParam,
) (*account.ListOrgsAdvanceResponse, bizerr.BizError) {
	client := getAccountSvcClient()

	resp, err := client.ListOrgsAdvance(ctx, req)
	if err != nil {
		return nil, wrapGrpcError(err)
	}
	if err := parseBaseResp(resp.BaseResp); err != nil {
		return nil, err
	}
	return resp, nil
}

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

	resp, err := client.GetProjectByID(ctx, req)
	if err != nil {
		return nil, wrapGrpcError(err)
	}
	if err := parseBaseResp(resp.BaseResp); err != nil {
		return nil, err
	}
	return resp, nil
}

func GetDBUsers(ctx context.Context, req *account.GetDBUsersReq) (*account.GetDBUsersResp, bizerr.BizError) {
	client := getAccountSvcClient()

	resp, err := client.GetDBUsers(ctx, req)
	if err != nil {
		return resp, wrapGrpcError(err)
	}
	if err := parseBaseResp(resp.BaseResp); err != nil {
		return nil, err
	}
	return resp, nil
}

func GetCloudAdminCredential(
	ctx context.Context,
	req *account.GetCloudAdminCredentialReq,
) (*account.GetCloudAdminCredentialRsp, bizerr.BizError) {
	client := getAccountSvcClient()

	resp, err := client.GetCloudAdminCredential(ctx, req)
	if err != nil {
		return resp, wrapGrpcError(err)
	}
	if err := parseBaseResp(resp.BaseResp); err != nil {
		return nil, err
	}
	return resp, nil
}

func SendEmailByLabels(
	ctx context.Context,
	req *account.SendEmailByLabelsReq,
) (*account.SendEmailByLabelsResp, bizerr.BizError) {
	client := getAccountSvcClient()

	resp, err := client.SendEmailByLabels(ctx, req)
	if err != nil {
		return resp, wrapGrpcError(err)
	}
	if err := parseBaseResp(resp.BaseResp); err != nil {
		return nil, err
	}
	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, wrapGrpcError(err)
	}
	if err := parseBaseResp(resp.BaseResp); err != nil {
		return nil, err
	}

	return resp, nil
}
