package centralhandler

import (
	"context"
	"fmt"
	"net/http"
	"sync"
	"time"

	"github.com/avast/retry-go"
	"github.com/pingcap/dbaas/billing2/billing_errors"
	"github.com/pingcap/dbaas/billing2/config"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/utils/auth0"
	"github.com/pingcap/dbaas/billing2/utils/httpclient"
	"github.com/pingcap/dbaas/billing2/utils/log"
	"github.com/tidbcloud/account/idl/pbgen/proto/account"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

const TenantStatusActive = "active"

type CentralHandlerImpl struct {
}

func centralEnabled() bool {
	return config.Get().GetBool(config.DBaaSCentralEnable)
}

func signCentralAuth(req *http.Request) error {
	auth0Domain, auth0ClientID, auth0ClientSecret, auth0Audience := config.Get().GetString(config.DBaaSCentralAuth0Domain), config.Get().GetString(config.DBaaSCentralAuth0ClientID), config.Get().GetString(config.DBaaSCentralAuth0ClientSecret), config.Get().GetString(config.DBaaSCentralAuth0Audience)
	token, err := auth0.GetClientToken(auth0Domain, auth0ClientID, auth0ClientSecret, auth0Audience)
	if err != nil {
		return billing_errors.NewSystemError(err)
	}
	req.Header.Add("Authorization", fmt.Sprintf("bearer %s", token))
	return nil
}

func getClient() httpclient.HTTPClient {
	return httpclient.NewClient(signCentralAuth, fmt.Sprintf("%s://%s", config.Get().GetString(config.DBaaSCentralScheme), config.Get().GetString(config.DBaaSCentralHost)), "/api/v1/admin/")
}

func convertOrg2Tenant(org *account.Org) forms.Tenant {
	return forms.Tenant{
		TenantID:                  uint(org.GetId()),
		Name:                      org.GetName(),
		Email:                     org.GetEmail(),
		ThirdPartyAccountProvider: org.GetThirdPartyAccountProvider(),
		ThirdPartyAccountCode:     org.GetThirdPartyAccountCode(),
		ThirdPartyFreeTrial:       org.GetThirdPartyFreeTrial(),
		Status:                    org.GetStatus(),
		IsMsp:                     org.GetIsMsp(),
		IsMspCustomer:             org.GetIsMspCustomer(),
		IsCPPOReseller:            org.GetIsCppo(),
		IsCPPOCustomer:            org.GetIsCppoCustomer(),
		Kind:                      org.GetKind(),
		OrgTag:                    org.GetOrgTag(),
		IsMCPOReseller:            org.GetIsMcpoPartner(),
		IsMCPOCustomer:            org.GetIsMcpoCustomer(),
		IsResalePartner:           org.GetIsResalePartner(),
		IsResaleCustomer:          org.GetIsResaleCustomer(),
	}
}

func (*CentralHandlerImpl) GetAllTenants() ([]forms.Tenant, error) {
	return getTenants(&account.OrgFilter{})
}

func (*CentralHandlerImpl) GetTenants(ids ...uint) ([]forms.Tenant, error) {
	idsUint64 := make([]uint64, len(ids))
	for i, id := range ids {
		idsUint64[i] = uint64(id)
	}
	return getTenants(&account.OrgFilter{Ids: idsUint64})
}

func getTenants(req *account.OrgFilter) ([]forms.Tenant, error) {
	var output []forms.Tenant
	if !centralEnabled() {
		return output, nil
	}
	err := retry.Do(func() error {
		ctx := context.Background()
		client := getCentralGRPCClient()
		resp, err := client.ListOrgs(ctx, req)
		if err != nil {
			return err
		}
		orgs := resp.Orgs
		output = make([]forms.Tenant, len(orgs))
		for i, org := range orgs {
			output[i] = convertOrg2Tenant(org)
		}
		return nil
	})
	if err != nil {
		log.Error("failed to get all tenants", zap.Error(err))
		return nil, err
	}
	return output, nil
}

func (impl *CentralHandlerImpl) GetMspCustomerScheduleInfo(customerID uint) (*forms.MspCustomerScheduleInfo, error) {
	if !centralEnabled() {
		return nil, nil
	}
	output, err := impl.GetPendingCustomerScheduleInfo(customerID, account.PartnerType_PARTNER_TYPE_MSP)
	if err != nil {
		return nil, err
	}
	if len(output) == 0 {
		return nil, billing_errors.ObjectNotExistsError
	}
	if len(output) > 1 {
		log.Info("too many schedule info for a customer", zap.Any("output", output))
		return nil, billing_errors.NewSystemError(nil)
	}
	return &forms.MspCustomerScheduleInfo{
		MspTenantID:      output[0].PartnerTenantID,
		CustomerTenantID: output[0].CustomerTenantID,
		Status:           output[0].Status,
		EffectedAt:       output[0].EffectedAt,
		ExpiredAt:        output[0].ExpiredAt,
	}, nil
}

func (*CentralHandlerImpl) GetPendingCustomerScheduleInfo(customerID uint, partnerType account.PartnerType) ([]*forms.PartnerCustomerScheduleInfo, error) {
	if !centralEnabled() {
		return nil, nil
	}
	var output []*forms.PartnerCustomerScheduleInfo
	err := retry.Do(func() error {
		ctx := context.Background()
		client := getCentralGRPCClient()
		req := &account.ListPartnerCustomersReq{PartnerCustomerIds: []uint64{uint64(customerID)}, PartnerType: partnerType, Status: []string{"pending"}}
		resp, err := client.ListPartnerCustomers(ctx, req)
		if err != nil {
			return err
		}
		orgs := resp.PartnerCustomers
		output = make([]*forms.PartnerCustomerScheduleInfo, len(orgs))
		for i, org := range orgs {
			output[i] = &forms.PartnerCustomerScheduleInfo{
				PartnerTenantID:  org.GetPartnerOrgId(),
				CustomerTenantID: org.GetCustomerOrgId(),
				Status:           org.GetStatus(),
				EffectedAt:       org.GetEffectedAt().AsTime(),
			}
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return output, nil
}

func (*CentralHandlerImpl) GetTenant(tenantID uint) (*forms.Tenant, error) {
	if !centralEnabled() {
		return &forms.Tenant{
			TenantID: tenantID,
			Status:   TenantStatusActive,
		}, nil
	}
	var tenant forms.Tenant
	err := retry.Do(func() error {
		ctx := context.Background()
		client := getCentralGRPCClient()
		req := &account.GetOrgByIDRequest{
			Id:      uint64(tenantID),
			IsBrief: true,
		}
		resp, err := client.GetOrgByID(ctx, req)
		if err != nil {
			return err
		}
		if resp.BaseResp.ErrCode == 49900005 {
			return billing_errors.NewObjectNotExistsError(fmt.Errorf("tenant %d not exits", tenantID))
		}
		org := resp.Org
		tenant = convertOrg2Tenant(org)
		log.Info("get tenant info from central", zap.Any("org", org), zap.Any("tenant", tenant))
		return nil
	})
	if err != nil {
		log.Error("failed to get tenant", zap.Error(err), zap.Uint("TenantID", tenantID))
		return nil, err
	}
	return &tenant, nil
}

func (*CentralHandlerImpl) DownloadFile(path string) ([]byte, error) {
	if !centralEnabled() {
		return []byte(""), nil
	}
	var err error
	var output []byte
	err = retry.Do(func() error {
		output, err = getClient().RequestRaw("GET", fmt.Sprintf("/uploaded/%s", path), nil, nil)
		return err
	})
	if err != nil {
		log.Error("failed to downloads file", zap.Error(err), zap.String("path", path))
		return nil, err
	}
	return output, nil
}

func (*CentralHandlerImpl) GetUser(userID uint) (*forms.User, error) {
	if !centralEnabled() {
		return &forms.User{
			UserID: userID,
		}, nil
	}
	var output *forms.User
	err := retry.Do(func() error {
		ctx := context.Background()
		client := getCentralGRPCClient()
		resp, err := client.GetUserByID(ctx, &account.GetUserByIDRequest{UserId: uint64(userID)})
		if err != nil {
			log.Error("failed to get user from central", zap.Error(err))
			return err
		}
		output = &forms.User{
			UserID: userID,
			Email:  resp.User.Email,
		}
		return nil
	})
	if err != nil {
		log.Error("failed to get all user", zap.Error(err), zap.Uint("userID", userID))
		return nil, err
	}
	return output, nil
}
func (impl *CentralHandlerImpl) GetUserListByOrgID(orgID uint, roles []string) ([]forms.User, error) {
	ctx := context.Background()
	filter := &account.ListUsersFilter{
		ScopeTypes: []account.ScopeType{account.ScopeType_SCOPE_TYPE_ORG},
		ScopeIds:   []uint64{uint64(orgID)},
		Roles:      roles,
	}
	return getUserListByFilter(ctx, filter)
}

func (impl *CentralHandlerImpl) GetUserListByProjectID(projectID uint, roles []string) ([]forms.User, error) {
	ctx := context.Background()
	filter := &account.ListUsersFilter{
		ScopeTypes: []account.ScopeType{account.ScopeType_SCOPE_TYPE_PROJECT},
		ScopeIds:   []uint64{uint64(projectID)},
		Roles:      roles,
	}
	return getUserListByFilter(ctx, filter)

}
func getUserListByFilter(ctx context.Context, filter *account.ListUsersFilter) ([]forms.User, error) {
	var output []forms.User
	err := retry.Do(func() error {
		client := getCentralGRPCClient()
		resp, err := client.ListUsersByFilter(ctx, &account.ListUsersByFilterRequest{
			Filter: filter,
		})
		if err != nil {
			log.Error("failed to get user from central", zap.Error(err))
			return err
		}
		for _, user := range resp.Users {
			if user.Status != 1 {
				continue
			}
			output = append(output, forms.User{
				UserID:    uint(user.Id),
				FirstName: user.FirstName,
				LastName:  user.LastName,
				Email:     user.Email,
			})
		}
		return nil
	})
	if err != nil {
		log.Error("failed to getUserListByFilter", zap.Error(err))
		return nil, err
	}
	return output, nil
}

var (
	centralCli     account.AccountAPIServiceClient
	centralSvcOnce sync.Once
)

func getCentralGRPCClient() account.AccountAPIServiceClient {
	centralSvcOnce.Do(func() {
		conn, err := grpc.DialContext(
			context.Background(),
			config.Get().GetString(config.AccountSvcAddress),
			grpc.WithTransportCredentials(insecure.NewCredentials()),
			grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)),
		)
		if err != nil {
			err = billing_errors.NewSystemError(err)
			log.Error("init core service client", zap.String("addr", config.Get().GetString(config.AccountSvcAddress)), zap.Error(err))
			panic(fmt.Sprintf("dial core-svc: %s", err))
		}

		centralCli = account.NewAccountAPIServiceClient(conn)
	})

	return centralCli
}

func (*CentralHandlerImpl) DeleteTenant(tenantID uint) error {
	if !centralEnabled() {
		return nil
	}

	ctx := context.Background()
	client := getCentralGRPCClient()
	req := &account.DeleteOrgRequest{
		OrgId: uint64(tenantID),
	}

	var err error = nil

	resp, e := client.DeleteOrgByID(ctx, req)
	if e != nil {
		err = billing_errors.NewSystemError(e)
	} else {
		if resp.BaseResp.ErrCode != 0 {
			err = billing_errors.NewSystemError(fmt.Errorf("invalid call central svc, err code %d", resp.BaseResp.ErrCode))
		}
	}

	if err != nil {
		log.Error("failed call account delete org", zap.Uint("tenantID", tenantID), zap.Error(err))
		return err
	}

	log.Info("success call delete delete org", zap.Uint("tenantID", tenantID))
	return nil
}
func (*CentralHandlerImpl) SendEmail(req *account.SendEmailReq) error {
	if !centralEnabled() {
		return nil
	}

	ctx := context.Background()
	client := getCentralGRPCClient()
	resp, err := client.SendEmail(ctx, req)
	if err != nil {
		err = billing_errors.NewSystemError(err)
		log.Error("failed call account send email", zap.Uint64("tenantID", req.OrgId), zap.Error(err))
		return err
	}

	if resp.BaseResp.ErrCode != 0 {
		// magic number for tiinf error ErrCodeConflict, if conflict means mail aleady sent, just ignore
		// we dont want to import tiinf error in this repo. it will create two error system in this repo.
		if resp.BaseResp.ErrCode == 49900409 {
			log.Info("mail already sent before", zap.Uint64("tenantID", req.OrgId))
			return nil
		}

		if resp.BaseResp.ErrCode == 49900001 {
			//just record error if send mail failed in invalid params
			//this caused by account manager is null in tenants.
			log.Info("mail send failed", zap.Uint64("tenantID", req.OrgId), zap.String("message", resp.BaseResp.ErrMsg))
			return nil
		}

		err = billing_errors.NewSystemError(fmt.Errorf("invalid call account svc, err code %d， error msg %s", resp.BaseResp.ErrCode, resp.BaseResp.ErrMsg))
		log.Error("failed call account send email ", zap.Uint64("tenantID", req.OrgId), zap.Error(err))
		return err
	}

	log.Info("success call account send email ", zap.Uint64("tenantID", req.OrgId))
	return nil
}

func (*CentralHandlerImpl) SendTenantEmailWithLabelOnce(tenantID uint, key string, templateID string, vars map[string]string, label account.MailLabels, cc []account.MailLabels) error {
	if !centralEnabled() {
		return nil
	}

	ctx := context.Background()
	client := getCentralGRPCClient()
	req := &account.SendEmailByLabelsReq{
		OrgId:        uint64(tenantID),
		TemplateId:   templateID,
		TemplateVars: vars,
		Scene:        "billing",
		Identifier:   key,
		ToLabel:      label,
		CcLabels:     cc,
	}
	resp, err := client.SendEmailByLabels(ctx, req)
	if err != nil {
		err = billing_errors.NewSystemError(err)
		log.Error("failed call account send email by labels", zap.Uint("tenantID", tenantID), zap.Error(err))
		return err
	}

	if resp.BaseResp.ErrCode != 0 {
		// magic number for tiinf error ErrCodeConflict, if conflict means mail aleady sent, just ignore
		// we dont want to import tiinf error in this repo. it will create two error system in this repo.
		if resp.BaseResp.ErrCode == 49900409 {
			log.Info("mail already sent before", zap.Uint("tenantID", tenantID), zap.String("key", key))
			return nil
		}

		if resp.BaseResp.ErrCode == 49900001 {
			//just record error if send mail failed in invalid params
			//this caused by account manager is null in tenants.
			log.Info("mail send failed", zap.Uint("tenantID", tenantID), zap.String("key", key), zap.String("message", resp.BaseResp.ErrMsg))
			return nil
		}

		err = billing_errors.NewSystemError(fmt.Errorf("invalid call account svc, err code %d， error msg %s", resp.BaseResp.ErrCode, resp.BaseResp.ErrMsg))
		log.Error("failed call account send email by labels", zap.Uint("tenantID", tenantID), zap.Error(err))
		return err
	}

	log.Info("success call account send email by labels", zap.Uint("tenantID", tenantID), zap.String("key", key))
	return nil
}

func (impl *CentralHandlerImpl) SendTenantAdminEmailOnce(tenantID uint, key string, templateID string, vars map[string]string) error {
	return impl.SendTenantEmailWithLabelOnce(tenantID, key, templateID, vars, account.MailLabels_MAIL_LABELS_ORG_CREATOR, nil)
}

func (impl *CentralHandlerImpl) SendTenantOwnerEmailOnce(tenantID uint, key string, templateID string, vars map[string]string) error {
	return impl.SendTenantEmailWithLabelOnce(tenantID, key, templateID, vars, account.MailLabels_MAIL_LABELS_ORG_OWNER, nil)
}

func (impl *CentralHandlerImpl) SendTenantManagerEmailOnce(tenantID uint, key string, templateID string, vars map[string]string) error {
	return impl.SendTenantEmailWithLabelOnce(tenantID, key, templateID, vars, account.MailLabels_MAIL_LABELS_ORG_MANAGER, nil)
}

func (*CentralHandlerImpl) ResetOnceEmailStatus(tenantID uint, key string) error {
	if !centralEnabled() {
		return nil
	}

	ctx := context.Background()
	client := getCentralGRPCClient()
	req := &account.ClearEmailUniqueIDReq{
		OrgId:      uint64(tenantID),
		Scene:      "billing",
		Identifier: key,
	}
	var err error = nil
	resp, e := client.ClearEmailUniqueID(ctx, req)
	if e != nil {
		err = billing_errors.NewSystemError(e)
	} else {
		if resp.BaseResp.ErrCode != 0 {
			err = billing_errors.NewSystemError(fmt.Errorf("invalid call core svc, err code %d", resp.BaseResp.ErrCode))
		}
	}
	if err != nil {
		log.Error("failed call account reset email status", zap.Uint("tenantID", tenantID), zap.Error(err))
		return err
	}

	log.Info("success call account reset email status", zap.Uint("tenantID", tenantID))
	return nil
}

func (impl *CentralHandlerImpl) GetProjectName(projectID uint) (string, error) {
	projectInfo, err := impl.GetProjectInfo(projectID)
	if err != nil {
		return "", err
	}
	return projectInfo.Name, nil
}

func (impl *CentralHandlerImpl) GetProjectInfo(projectID uint) (ret *forms.Project, err error) {
	if !centralEnabled() {
		return
	}
	err = retry.Do(func() error {
		ctx := context.Background()
		client := getCentralGRPCClient()
		req := &account.GetProjectByIDRequest{
			Id: uint64(projectID),
		}
		resp, e := client.GetProjectByID(ctx, req)
		if e != nil {
			err = billing_errors.NewSystemError(e)
		} else if resp.BaseResp.ErrCode != 0 {
			err = billing_errors.NewSystemError(fmt.Errorf("invalid call core svc, err code %d", resp.BaseResp.ErrCode))
		}
		if err != nil {
			return err
		}
		log.Info("get project info ", zap.Any("project", resp))

		ret = &forms.Project{
			ID:       uint(resp.Project.Id),
			TenantID: uint(resp.Project.TenantId),
			Name:     resp.Project.Name,
			Status:   resp.Project.Status,
			Type:     int32(resp.Project.GetType()),
		}
		return nil
	})
	if err != nil {
		log.Error("failed get project info", zap.Uint("projectID", projectID), zap.Error(err))
		return nil, err
	}
	return ret, nil
}

func (impl *CentralHandlerImpl) GetTenantIdByOpenAPIAccess(apiKey string) (tenantID uint64, err error) {
	if !centralEnabled() {
		return 0, nil
	}
	err = retry.Do(func() error {
		client := getCentralGRPCClient()
		accReq := account.GetOpenAPIAccessReq{
			PublicKey: apiKey,
		}
		ctx := context.Background()

		resp, e := client.GetOpenAPIAccess(ctx, &accReq)
		if e != nil {
			err := billing_errors.NewSystemError(e)
			return err
		}
		tenantID = resp.Org.Id
		return nil
	})
	if err != nil {
		log.Error("failed GetOpenAPIAccess Name", zap.String("apiKey", apiKey), zap.Error(err))
		return 0, err
	}
	return tenantID, err
}

func (impl *CentralHandlerImpl) ListProjects(tenantID uint, containsDeleted bool) (ret []*forms.Project, err error) {
	if !centralEnabled() {
		return
	}
	err = retry.Do(func() error {
		ctx := context.Background()
		client := getCentralGRPCClient()
		req := &account.ProjectFilter{
			OrgIds: []uint64{uint64(tenantID)},
		}
		if !containsDeleted {
			req.Status = []string{"active"}
		}
		resp, e := client.ListProjects(ctx, req)
		if e != nil {
			err = billing_errors.NewSystemError(e)
		} else if resp.BaseResp.ErrCode != 0 {
			err = billing_errors.NewSystemError(fmt.Errorf("invalid call core svc, err code %d", resp.BaseResp.ErrCode))
		}
		if err != nil {
			return err
		}
		ret = make([]*forms.Project, len(resp.Projects))
		for i, p := range resp.Projects {
			ret[i] = &forms.Project{
				ID:       uint(p.GetId()),
				TenantID: uint(p.GetTenantId()),
				Name:     p.GetName(),
				Status:   p.GetStatus(),
			}
		}
		return nil
	})
	if err != nil {
		log.Error("failed list projects", zap.Error(err), zap.Uint("tenantID", tenantID))
		return nil, err
	}
	return ret, nil
}

func (impl *CentralHandlerImpl) UpdateAccountThirdPartyInfo(tenantID uint, thirdPartyAccountCode string) error {
	if !centralEnabled() {
		return nil
	}
	err := retry.Do(func() error {
		client := getCentralGRPCClient()
		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
		defer cancel()
		_, err := client.UpdateOrg(ctx, &account.UpdateOrgRequest{Id: uint64(tenantID), ThirdPartyAccountCode: thirdPartyAccountCode})
		return err
	})
	if err != nil {
		log.Error("failed update third party info", zap.Error(err), zap.Uint("tenantID", tenantID))
		return err
	}
	return nil
}

func (impl *CentralHandlerImpl) ListPartnerCustomers(tenantID uint) (ret []*forms.Customer, err error) {
	if !centralEnabled() {
		return
	}
	var resp *account.ListPartnerCustomersResp
	err = retry.Do(func() error {
		client := getCentralGRPCClient()
		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
		defer cancel()
		resp, err = client.ListPartnerCustomers(ctx, &account.ListPartnerCustomersReq{PartnerIds: []uint64{uint64(tenantID)}})
		return err
	})
	if err != nil {
		log.Error("failed update third party info", zap.Error(err), zap.Uint("tenantID", tenantID))
		return nil, err
	}
	log.Info("list partner customers", zap.Uint("tenantID", tenantID), zap.Any("resp", resp))
	customers := make([]*forms.Customer, len(resp.PartnerCustomers))
	for i, c := range resp.PartnerCustomers {
		cus, err := impl.GetTenant(uint(c.GetCustomerOrgId()))
		if err != nil {
			return nil, err
		}
		customers[i] = &forms.Customer{
			ID:   fmt.Sprint(cus.TenantID),
			Name: cus.Name,
		}
	}
	return customers, nil
}

func (impl *CentralHandlerImpl) IsPartnersCustomer(partnerID uint, customerID uint) (bool, error) {
	if !centralEnabled() {
		return false, nil
	}
	var err error
	var resp *account.ListPartnerCustomersResp
	err = retry.Do(func() error {
		client := getCentralGRPCClient()
		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
		defer cancel()
		resp, err = client.ListPartnerCustomers(ctx, &account.ListPartnerCustomersReq{
			PartnerIds:         []uint64{uint64(partnerID)},
			PartnerCustomerIds: []uint64{uint64(customerID)},
		})
		return err
	})
	if err != nil {
		return false, err
	}
	log.Info("list partner customers", zap.Uint("partnerID", partnerID), zap.Uint("customerID", customerID), zap.Any("resp", resp))
	return len(resp.PartnerCustomers) == 1, nil
}

func (impl *CentralHandlerImpl) IsHitFeatureFlag(orgID uint64, flag string) (bool, error) {
	if !centralEnabled() {
		return false, nil
	}
	var resp *account.HitFeatureFlagRsp
	err := retry.Do(func() error {
		client := getCentralGRPCClient()
		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
		defer cancel()
		var err error
		resp, err = client.IsHitFeatureFlag(ctx, &account.HitFeatureFlagReq{
			OrgId:    orgID,
			FlagName: flag,
		})
		return err
	})
	if err != nil {
		log.Error("failed to check feature flag", zap.Error(err), zap.Uint64("orgID", orgID), zap.String("flag", flag))
		return false, err
	}
	return resp.IsHit, nil
}

func (impl *CentralHandlerImpl) ConfigFeatureFlagOrg(orgID uint64, flag string) error {
	if !centralEnabled() {
		return nil
	}
	var err error
	var resp *account.ConfigFeatureFlagOrgRsp
	err = retry.Do(func() error {
		client := getCentralGRPCClient()
		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
		defer cancel()
		resp, err = client.ConfigFeatureFlagOrg(ctx, &account.ConfigFeatureFlagOrgReq{
			OrgIds:   []uint64{orgID},
			FlagName: flag,
		})
		return err
	})
	if err != nil {
		log.Error("failed to ConfigFeatureFlagOrg", zap.Error(err), zap.Uint64("orgID", orgID), zap.String("flag", flag))
		return err
	}
	log.Info("success to ConfigFeatureFlagOrg", zap.Uint64("orgID", orgID), zap.String("flag", flag), zap.Any("resp", resp))
	return nil
}
