package grpc

import (
	"context"
	walletv1 "hyapp.local/api/proto/wallet/v1"
	"hyapp/pkg/xerr"
	resourcedomain "hyapp/services/wallet-service/internal/domain/resource"
)

func (s *Server) ListResources(ctx context.Context, req *walletv1.ListResourcesRequest) (*walletv1.ListResourcesResponse, error) {
	items, total, err := s.svc.ListResources(ctx, resourcedomain.ListResourcesQuery{
		AppCode:          req.GetAppCode(),
		ResourceType:     req.GetResourceType(),
		Status:           req.GetStatus(),
		Keyword:          req.GetKeyword(),
		Page:             req.GetPage(),
		PageSize:         req.GetPageSize(),
		ActiveOnly:       req.GetActiveOnly(),
		ManagerGrantOnly: req.GetManagerGrantOnly(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &walletv1.ListResourcesResponse{Resources: make([]*walletv1.Resource, 0, len(items)), Total: total}
	for _, item := range items {
		resp.Resources = append(resp.Resources, resourceToProto(item))
	}
	return resp, nil
}

func (s *Server) GetResource(ctx context.Context, req *walletv1.GetResourceRequest) (*walletv1.GetResourceResponse, error) {
	resource, err := s.svc.GetResource(ctx, req.GetAppCode(), req.GetResourceId())
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.GetResourceResponse{Resource: resourceToProto(resource)}, nil
}

func (s *Server) CreateResource(ctx context.Context, req *walletv1.CreateResourceRequest) (*walletv1.ResourceResponse, error) {
	resource, err := s.svc.CreateResource(ctx, resourceCommandFromCreate(req))
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.ResourceResponse{Resource: resourceToProto(resource)}, nil
}

func (s *Server) UpdateResource(ctx context.Context, req *walletv1.UpdateResourceRequest) (*walletv1.ResourceResponse, error) {
	resource, err := s.svc.UpdateResource(ctx, resourceCommandFromUpdate(req))
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.ResourceResponse{Resource: resourceToProto(resource)}, nil
}

func (s *Server) SetResourceStatus(ctx context.Context, req *walletv1.SetResourceStatusRequest) (*walletv1.ResourceResponse, error) {
	resource, err := s.svc.SetResourceStatus(ctx, resourcedomain.StatusCommand{
		AppCode:        req.GetAppCode(),
		ID:             req.GetResourceId(),
		Status:         req.GetStatus(),
		OperatorUserID: req.GetOperatorUserId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.ResourceResponse{Resource: resourceToProto(resource)}, nil
}

func (s *Server) DeleteResource(ctx context.Context, req *walletv1.DeleteResourceRequest) (*walletv1.ResourceResponse, error) {
	resource, err := s.svc.DeleteResource(ctx, resourcedomain.StatusCommand{
		AppCode:        req.GetAppCode(),
		ID:             req.GetResourceId(),
		OperatorUserID: req.GetOperatorUserId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.ResourceResponse{Resource: resourceToProto(resource)}, nil
}

func (s *Server) BatchDeleteResources(ctx context.Context, req *walletv1.BatchDeleteResourcesRequest) (*walletv1.BatchDeleteResourcesResponse, error) {
	resources, err := s.svc.BatchDeleteResources(ctx, resourcedomain.BatchDeleteResourcesCommand{
		AppCode:        req.GetAppCode(),
		ResourceIDs:    req.GetResourceIds(),
		OperatorUserID: req.GetOperatorUserId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &walletv1.BatchDeleteResourcesResponse{Resources: make([]*walletv1.Resource, 0, len(resources))}
	for _, resource := range resources {
		resp.Resources = append(resp.Resources, resourceToProto(resource))
	}
	return resp, nil
}

func (s *Server) ListResourceGroups(ctx context.Context, req *walletv1.ListResourceGroupsRequest) (*walletv1.ListResourceGroupsResponse, error) {
	items, total, err := s.svc.ListResourceGroups(ctx, resourcedomain.ListResourceGroupsQuery{
		AppCode:    req.GetAppCode(),
		Status:     req.GetStatus(),
		Keyword:    req.GetKeyword(),
		Page:       req.GetPage(),
		PageSize:   req.GetPageSize(),
		ActiveOnly: req.GetActiveOnly(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &walletv1.ListResourceGroupsResponse{Groups: make([]*walletv1.ResourceGroup, 0, len(items)), Total: total}
	for _, item := range items {
		resp.Groups = append(resp.Groups, resourceGroupToProto(item))
	}
	return resp, nil
}

func (s *Server) GetResourceGroup(ctx context.Context, req *walletv1.GetResourceGroupRequest) (*walletv1.GetResourceGroupResponse, error) {
	group, err := s.svc.GetResourceGroup(ctx, req.GetAppCode(), req.GetGroupId())
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	contentHash, err := resourcedomain.ResourceGroupContentHash(group)
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.GetResourceGroupResponse{Group: resourceGroupToProto(group), SourceContentHash: contentHash}, nil
}

func (s *Server) CreateResourceGroup(ctx context.Context, req *walletv1.CreateResourceGroupRequest) (*walletv1.ResourceGroupResponse, error) {
	group, err := s.svc.CreateResourceGroup(ctx, resourceGroupCommandFromCreate(req))
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.ResourceGroupResponse{Group: resourceGroupToProto(group)}, nil
}

func (s *Server) UpdateResourceGroup(ctx context.Context, req *walletv1.UpdateResourceGroupRequest) (*walletv1.ResourceGroupResponse, error) {
	group, err := s.svc.UpdateResourceGroup(ctx, resourceGroupCommandFromUpdate(req))
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.ResourceGroupResponse{Group: resourceGroupToProto(group)}, nil
}

func (s *Server) SetResourceGroupStatus(ctx context.Context, req *walletv1.SetResourceGroupStatusRequest) (*walletv1.ResourceGroupResponse, error) {
	group, err := s.svc.SetResourceGroupStatus(ctx, resourcedomain.StatusCommand{
		AppCode:        req.GetAppCode(),
		ID:             req.GetGroupId(),
		Status:         req.GetStatus(),
		OperatorUserID: req.GetOperatorUserId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.ResourceGroupResponse{Group: resourceGroupToProto(group)}, nil
}

func (s *Server) ListGiftConfigs(ctx context.Context, req *walletv1.ListGiftConfigsRequest) (*walletv1.ListGiftConfigsResponse, error) {
	items, total, err := s.svc.ListGiftConfigs(ctx, resourcedomain.ListGiftConfigsQuery{
		AppCode:      req.GetAppCode(),
		Status:       req.GetStatus(),
		Keyword:      req.GetKeyword(),
		GiftTypeCode: req.GetGiftTypeCode(),
		Page:         req.GetPage(),
		PageSize:     req.GetPageSize(),
		ActiveOnly:   req.GetActiveOnly(),
		RegionID:     req.GetRegionId(),
		FilterRegion: req.GetFilterRegion(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &walletv1.ListGiftConfigsResponse{Gifts: make([]*walletv1.GiftConfig, 0, len(items)), Total: total}
	for _, item := range items {
		resp.Gifts = append(resp.Gifts, giftConfigToProto(item))
	}
	return resp, nil
}

func (s *Server) ListGiftTypeConfigs(ctx context.Context, req *walletv1.ListGiftTypeConfigsRequest) (*walletv1.ListGiftTypeConfigsResponse, error) {
	items, err := s.svc.ListGiftTypeConfigs(ctx, resourcedomain.ListGiftTypeConfigsQuery{
		AppCode:    req.GetAppCode(),
		Status:     req.GetStatus(),
		ActiveOnly: req.GetActiveOnly(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &walletv1.ListGiftTypeConfigsResponse{GiftTypes: make([]*walletv1.GiftTypeConfig, 0, len(items))}
	for _, item := range items {
		resp.GiftTypes = append(resp.GiftTypes, giftTypeConfigToProto(item))
	}
	return resp, nil
}

func (s *Server) GetGiftCatalogVersion(ctx context.Context, req *walletv1.GetGiftCatalogVersionRequest) (*walletv1.GetGiftCatalogVersionResponse, error) {
	version, err := s.svc.GetGiftCatalogVersion(ctx, req.GetAppCode())
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.GetGiftCatalogVersionResponse{Version: version}, nil
}

func (s *Server) CreateGiftConfig(ctx context.Context, req *walletv1.CreateGiftConfigRequest) (*walletv1.GiftConfigResponse, error) {
	gift, err := s.svc.CreateGiftConfig(ctx, giftConfigCommandFromCreate(req))
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.GiftConfigResponse{Gift: giftConfigToProto(gift)}, nil
}

func (s *Server) BatchCreateGiftConfigs(ctx context.Context, req *walletv1.BatchCreateGiftConfigsRequest) (*walletv1.BatchCreateGiftConfigsResponse, error) {
	commands := make([]resourcedomain.GiftConfigCommand, 0, len(req.GetItems()))
	for _, item := range req.GetItems() {
		command := giftConfigCommandFromCreate(item)
		command.AppCode = req.GetAppCode()
		if command.OperatorUserID == 0 {
			command.OperatorUserID = req.GetOperatorUserId()
		}
		commands = append(commands, command)
	}
	gifts, err := s.svc.BatchCreateGiftConfigs(ctx, req.GetAppCode(), commands, req.GetOperatorUserId())
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &walletv1.BatchCreateGiftConfigsResponse{Gifts: make([]*walletv1.GiftConfig, 0, len(gifts))}
	for _, gift := range gifts {
		resp.Gifts = append(resp.Gifts, giftConfigToProto(gift))
	}
	return resp, nil
}

func (s *Server) UpdateGiftConfig(ctx context.Context, req *walletv1.UpdateGiftConfigRequest) (*walletv1.GiftConfigResponse, error) {
	gift, err := s.svc.UpdateGiftConfig(ctx, giftConfigCommandFromUpdate(req))
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.GiftConfigResponse{Gift: giftConfigToProto(gift)}, nil
}

func (s *Server) UpsertGiftTypeConfig(ctx context.Context, req *walletv1.UpsertGiftTypeConfigRequest) (*walletv1.GiftTypeConfigResponse, error) {
	item, err := s.svc.UpsertGiftTypeConfig(ctx, resourcedomain.GiftTypeConfigCommand{
		AppCode:        req.GetAppCode(),
		TypeCode:       req.GetTypeCode(),
		Name:           req.GetName(),
		TabKey:         req.GetTabKey(),
		Status:         req.GetStatus(),
		SortOrder:      req.GetSortOrder(),
		OperatorUserID: req.GetOperatorUserId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.GiftTypeConfigResponse{GiftType: giftTypeConfigToProto(item)}, nil
}

func (s *Server) SetGiftConfigStatus(ctx context.Context, req *walletv1.SetGiftConfigStatusRequest) (*walletv1.GiftConfigResponse, error) {
	gift, err := s.svc.SetGiftConfigStatus(ctx, resourcedomain.StatusCommand{
		AppCode:        req.GetAppCode(),
		StringID:       req.GetGiftId(),
		Status:         req.GetStatus(),
		OperatorUserID: req.GetOperatorUserId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.GiftConfigResponse{Gift: giftConfigToProto(gift)}, nil
}

func (s *Server) DeleteGiftConfig(ctx context.Context, req *walletv1.DeleteGiftConfigRequest) (*walletv1.GiftConfigResponse, error) {
	gift, err := s.svc.DeleteGiftConfig(ctx, resourcedomain.StatusCommand{
		AppCode:        req.GetAppCode(),
		StringID:       req.GetGiftId(),
		OperatorUserID: req.GetOperatorUserId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.GiftConfigResponse{Gift: giftConfigToProto(gift)}, nil
}

func (s *Server) GrantResource(ctx context.Context, req *walletv1.GrantResourceRequest) (*walletv1.ResourceGrantResponse, error) {
	grant, err := s.svc.GrantResource(ctx, resourcedomain.GrantResourceCommand{
		AppCode:        req.GetAppCode(),
		CommandID:      req.GetCommandId(),
		TargetUserID:   req.GetTargetUserId(),
		ResourceID:     req.GetResourceId(),
		Quantity:       req.GetQuantity(),
		DurationMS:     req.GetDurationMs(),
		Reason:         req.GetReason(),
		OperatorUserID: req.GetOperatorUserId(),
		GrantSource:    req.GetGrantSource(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.ResourceGrantResponse{Grant: resourceGrantToProto(grant)}, nil
}

func (s *Server) GrantResourceGroup(ctx context.Context, req *walletv1.GrantResourceGroupRequest) (*walletv1.ResourceGrantResponse, error) {
	grant, err := s.svc.GrantResourceGroup(ctx, resourcedomain.GrantResourceGroupCommand{
		AppCode:        req.GetAppCode(),
		CommandID:      req.GetCommandId(),
		TargetUserID:   req.GetTargetUserId(),
		GroupID:        req.GetGroupId(),
		Reason:         req.GetReason(),
		OperatorUserID: req.GetOperatorUserId(),
		GrantSource:    req.GetGrantSource(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.ResourceGrantResponse{Grant: resourceGrantToProto(grant)}, nil
}

func (s *Server) GetResourceGrant(ctx context.Context, req *walletv1.GetResourceGrantRequest) (*walletv1.ResourceGrantResponse, error) {
	grant, err := s.svc.GetResourceGrant(ctx, req.GetAppCode(), req.GetGrantId())
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.ResourceGrantResponse{Grant: resourceGrantToProto(grant)}, nil
}

func (s *Server) PinResourceGroupSnapshot(ctx context.Context, req *walletv1.PinResourceGroupSnapshotRequest) (*walletv1.PinResourceGroupSnapshotResponse, error) {
	item, err := s.svc.PinResourceGroupSnapshot(ctx, resourcedomain.PinResourceGroupSnapshotCommand{
		AppCode: req.GetAppCode(), GroupID: req.GetGroupId(), PinKey: req.GetPinKey(), OperatorUserID: req.GetOperatorUserId(),
		ExpectedGroupUpdatedAtMS: req.GetExpectedGroupUpdatedAtMs(), ExpectedSourceContentHash: req.GetExpectedSourceContentHash(),
		RequiredRegionIDs: req.GetRequiredRegionIds(), RequiredAllRegions: req.GetRequiredAllRegions(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.PinResourceGroupSnapshotResponse{Snapshot: resourceGroupSnapshotToProto(item)}, nil
}

func (s *Server) GrantPinnedResourceGroup(ctx context.Context, req *walletv1.GrantPinnedResourceGroupRequest) (*walletv1.ResourceGrantResponse, error) {
	grant, err := s.svc.GrantPinnedResourceGroup(ctx, resourcedomain.GrantPinnedResourceGroupCommand{
		AppCode: req.GetAppCode(), CommandID: req.GetCommandId(), TargetUserID: req.GetTargetUserId(),
		SnapshotID: req.GetSnapshotId(), Reason: req.GetReason(), OperatorUserID: req.GetOperatorUserId(),
		GrantSource: req.GetGrantSource(), ExpectedSnapshotHash: req.GetExpectedSnapshotHash(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.ResourceGrantResponse{Grant: resourceGrantToProto(grant)}, nil
}

func (s *Server) RevokeResourceGrant(ctx context.Context, req *walletv1.RevokeResourceGrantRequest) (*walletv1.ResourceGrantResponse, error) {
	grant, err := s.svc.RevokeResourceGrant(ctx, resourcedomain.RevokeResourceGrantCommand{
		AppCode:        req.GetAppCode(),
		RequestID:      req.GetRequestId(),
		GrantID:        req.GetGrantId(),
		Reason:         req.GetReason(),
		OperatorUserID: req.GetOperatorUserId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.ResourceGrantResponse{Grant: resourceGrantToProto(grant)}, nil
}

func (s *Server) RevokeUserResource(ctx context.Context, req *walletv1.RevokeUserResourceRequest) (*walletv1.RevokeUserResourceResponse, error) {
	resource, err := s.svc.RevokeUserResource(ctx, resourcedomain.RevokeUserResourceCommand{
		RequestID:      req.GetRequestId(),
		AppCode:        req.GetAppCode(),
		UserID:         req.GetUserId(),
		EntitlementID:  req.GetEntitlementId(),
		Reason:         req.GetReason(),
		OperatorUserID: req.GetOperatorUserId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.RevokeUserResourceResponse{Resource: userResourceToProto(resource)}, nil
}

func (s *Server) ListUserResources(ctx context.Context, req *walletv1.ListUserResourcesRequest) (*walletv1.ListUserResourcesResponse, error) {
	items, err := s.svc.ListUserResources(ctx, resourcedomain.ListUserResourcesQuery{
		AppCode:      req.GetAppCode(),
		UserID:       req.GetUserId(),
		ResourceType: req.GetResourceType(),
		ActiveOnly:   req.GetActiveOnly(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &walletv1.ListUserResourcesResponse{Resources: make([]*walletv1.UserResourceEntitlement, 0, len(items))}
	for _, item := range items {
		resp.Resources = append(resp.Resources, userResourceToProto(item))
	}
	return resp, nil
}

func (s *Server) EquipUserResource(ctx context.Context, req *walletv1.EquipUserResourceRequest) (*walletv1.EquipUserResourceResponse, error) {
	item, err := s.svc.EquipUserResource(ctx, resourcedomain.EquipUserResourceCommand{
		RequestID:     req.GetRequestId(),
		CommandID:     req.GetCommandId(),
		AppCode:       req.GetAppCode(),
		UserID:        req.GetUserId(),
		ResourceID:    req.GetResourceId(),
		EntitlementID: req.GetEntitlementId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.EquipUserResourceResponse{Resource: userResourceToProto(item)}, nil
}

func (s *Server) UnequipUserResource(ctx context.Context, req *walletv1.UnequipUserResourceRequest) (*walletv1.UnequipUserResourceResponse, error) {
	result, err := s.svc.UnequipUserResource(ctx, resourcedomain.UnequipUserResourceCommand{
		RequestID:    req.GetRequestId(),
		AppCode:      req.GetAppCode(),
		UserID:       req.GetUserId(),
		ResourceType: req.GetResourceType(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.UnequipUserResourceResponse{
		ResourceType: result.ResourceType,
		Unequipped:   result.Unequipped,
		UpdatedAtMs:  result.UpdatedAtMS,
	}, nil
}

func (s *Server) BatchGetUserEquippedResources(ctx context.Context, req *walletv1.BatchGetUserEquippedResourcesRequest) (*walletv1.BatchGetUserEquippedResourcesResponse, error) {
	items, err := s.svc.BatchGetUserEquippedResources(ctx, resourcedomain.BatchGetUserEquippedResourcesQuery{
		AppCode:         req.GetAppCode(),
		UserIDs:         req.GetUserIds(),
		ResourceTypes:   req.GetResourceTypes(),
		VIPBenefitCodes: req.GetVipBenefitCodes(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &walletv1.BatchGetUserEquippedResourcesResponse{Users: make([]*walletv1.UserEquippedResources, 0, len(items))}
	for _, item := range items {
		user := &walletv1.UserEquippedResources{
			UserId:                 item.UserID,
			Resources:              make([]*walletv1.UserResourceEntitlement, 0, len(item.Resources)),
			AllowedVipBenefitCodes: append([]string(nil), item.AllowedVIPBenefitCodes...),
			EffectiveVipLevel:      item.EffectiveVIPLevel,
		}
		for _, resource := range item.Resources {
			user.Resources = append(user.Resources, userResourceToProto(resource))
		}
		resp.Users = append(resp.Users, user)
	}
	return resp, nil
}

func (s *Server) ListResourceGrants(ctx context.Context, req *walletv1.ListResourceGrantsRequest) (*walletv1.ListResourceGrantsResponse, error) {
	items, total, err := s.svc.ListResourceGrants(ctx, resourcedomain.ListResourceGrantsQuery{
		AppCode:         req.GetAppCode(),
		TargetUserID:    req.GetTargetUserId(),
		Status:          req.GetStatus(),
		OperatorUserIDs: append([]int64(nil), req.GetOperatorUserIds()...),
		GrantSource:     req.GetGrantSource(),
		Page:            req.GetPage(),
		PageSize:        req.GetPageSize(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &walletv1.ListResourceGrantsResponse{Grants: make([]*walletv1.ResourceGrant, 0, len(items)), Total: total}
	for _, item := range items {
		resp.Grants = append(resp.Grants, resourceGrantToProto(item))
	}
	return resp, nil
}

func (s *Server) ListResourceShopItems(ctx context.Context, req *walletv1.ListResourceShopItemsRequest) (*walletv1.ListResourceShopItemsResponse, error) {
	items, total, err := s.svc.ListResourceShopItems(ctx, resourcedomain.ListResourceShopItemsQuery{
		AppCode:      req.GetAppCode(),
		ResourceType: req.GetResourceType(),
		Status:       req.GetStatus(),
		Keyword:      req.GetKeyword(),
		Page:         req.GetPage(),
		PageSize:     req.GetPageSize(),
		ActiveOnly:   req.GetActiveOnly(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &walletv1.ListResourceShopItemsResponse{Items: make([]*walletv1.ResourceShopItem, 0, len(items)), Total: total}
	for _, item := range items {
		resp.Items = append(resp.Items, resourceShopItemToProto(item))
	}
	return resp, nil
}

func (s *Server) UpsertResourceShopItems(ctx context.Context, req *walletv1.UpsertResourceShopItemsRequest) (*walletv1.UpsertResourceShopItemsResponse, error) {
	items, err := s.svc.UpsertResourceShopItems(ctx, resourcedomain.ResourceShopItemsCommand{
		AppCode:        req.GetAppCode(),
		Items:          resourceShopItemInputs(req.GetItems()),
		OperatorUserID: req.GetOperatorUserId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &walletv1.UpsertResourceShopItemsResponse{Items: make([]*walletv1.ResourceShopItem, 0, len(items))}
	for _, item := range items {
		resp.Items = append(resp.Items, resourceShopItemToProto(item))
	}
	return resp, nil
}

func (s *Server) SetResourceShopItemStatus(ctx context.Context, req *walletv1.SetResourceShopItemStatusRequest) (*walletv1.ResourceShopItemResponse, error) {
	item, err := s.svc.SetResourceShopItemStatus(ctx, resourcedomain.ResourceShopItemStatusCommand{
		AppCode:        req.GetAppCode(),
		ShopItemID:     req.GetShopItemId(),
		Status:         req.GetStatus(),
		OperatorUserID: req.GetOperatorUserId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &walletv1.ResourceShopItemResponse{Item: resourceShopItemToProto(item)}, nil
}

func (s *Server) ListResourceShopPurchaseOrders(ctx context.Context, req *walletv1.ListResourceShopPurchaseOrdersRequest) (*walletv1.ListResourceShopPurchaseOrdersResponse, error) {
	items, total, err := s.svc.ListResourceShopPurchaseOrders(ctx, resourcedomain.ListResourceShopPurchaseOrdersQuery{
		AppCode:      req.GetAppCode(),
		UserID:       req.GetUserId(),
		ResourceType: req.GetResourceType(),
		Status:       req.GetStatus(),
		Keyword:      req.GetKeyword(),
		Page:         req.GetPage(),
		PageSize:     req.GetPageSize(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	resp := &walletv1.ListResourceShopPurchaseOrdersResponse{Orders: make([]*walletv1.ResourceShopPurchaseOrder, 0, len(items)), Total: total}
	for _, item := range items {
		resp.Orders = append(resp.Orders, resourceShopPurchaseOrderToProto(item))
	}
	return resp, nil
}

func (s *Server) PurchaseResourceShopItem(ctx context.Context, req *walletv1.PurchaseResourceShopItemRequest) (*walletv1.PurchaseResourceShopItemResponse, error) {
	receipt, err := s.svc.PurchaseResourceShopItem(ctx, resourcedomain.ResourceShopPurchaseCommand{
		AppCode:    req.GetAppCode(),
		CommandID:  req.GetCommandId(),
		UserID:     req.GetUserId(),
		ShopItemID: req.GetShopItemId(),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return resourceShopPurchaseReceiptToProto(receipt), nil
}
