// ユーザーにアイテムを付与する
    // ユーザーにアイテムを付与するときは直接GrantItemsToUserを呼ぶんじゃなくてこれを呼ぶ
    public static async Task <List <GrantedItemInstance> > GrantItemsToUserAsync(FunctionExecutionContext <dynamic> context, List <string> itemIdList)
    {
        var serverApi = new PlayFabServerInstanceAPI(context.ApiSettings, context.AuthenticationContext);

        // アイテム付与前のインベントリ情報を保持しておく
        var beforeUserInventory = await DataProcessor.GetUserInventoryAsync(context);

        var result = await serverApi.GrantItemsToUserAsync(new GrantItemsToUserRequest()
        {
            PlayFabId = context.CallerEntityProfile.Lineage.MasterPlayerAccountId,
            ItemIds   = itemIdList
        });

        var grantedItemList = result.Result.ItemGrantResults;

        // 付与したアイテムが未所持モンスターだった場合新規でモンスターデータを作成し追加
        var monsterList = grantedItemList.Where(i => ItemUtil.GetItemType(i) == ItemType.Monster).ToList();

        if (monsterList.Any())
        {
            var monsterMasterList = await DataProcessor.GetMasterAsyncOf <MonsterMB>(context);

            var notHaveMonsterList = monsterList.Where(i => !beforeUserInventory.userMonsterList.Any(u => u.monsterId == ItemUtil.GetItemId(i))).ToList();

            // 未所持のモンスターデータを作成する
            foreach (var itemInstance in notHaveMonsterList)
            {
                var level      = 1;
                var monster    = monsterMasterList.First(m => m.id == ItemUtil.GetItemId(itemInstance));
                var status     = MonsterUtil.GetMonsterStatus(monster, level);
                var customData = new UserMonsterCustomData()
                {
                    level  = level,
                    exp    = 0,
                    hp     = status.hp,
                    attack = status.attack,
                    heal   = status.heal,
                    grade  = monster.initialGrade,
                };
                await DataProcessor.UpdateUserMonsterCustomDataAsync(context, itemInstance.ItemInstanceId, customData);
            }
        }

        return(grantedItemList);
    }
        public static async Task <dynamic> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            try{
                string body = await req.ReadAsStringAsync();

                var context = JsonConvert.DeserializeObject <FunctionExecutionContext <dynamic> >(body);
                var request = JsonConvert.DeserializeObject <FunctionExecutionContext <MonsterLevelUpApiRequest> >(body).FunctionArgument;

                // 対象のモンスターを取得
                var userInventory = await DataProcessor.GetUserInventoryAsync(context);

                var userMonster = userInventory.userMonsterList.FirstOrDefault(u => u.id == request.userMonsterId);
                PMApiUtil.ErrorIf(userMonster == null, PMErrorCode.Unknown, "invalid userMonsterId");

                // 経験値を十分に保持しているかチェック
                var exp = userInventory.userPropertyList.FirstOrDefault(u => u.propertyId == (long)PropertyType.MonsterExp);
                PMApiUtil.ErrorIf(exp == null || exp.num < request.exp, PMErrorCode.Unknown, "not enough exp");

                // 何レベになるか計算
                var levelUpTableList = await DataProcessor.GetMasterAsyncOf <MonsterLevelUpTableMB>(context);

                var afterExp           = userMonster.customData.exp + request.exp;
                var targetLevelUpTable = levelUpTableList.OrderBy(m => m.id).LastOrDefault(m => m.totalRequiredExp <= afterExp);
                PMApiUtil.ErrorIf(targetLevelUpTable == null, PMErrorCode.Unknown, "invalid levelUpTable");
                var afterLevel = targetLevelUpTable.level;

                // 対象のモンスターがマスタに存在するかチェック
                var monsterList = await DataProcessor.GetMasterAsyncOf <MonsterMB>(context);

                var monster = monsterList.FirstOrDefault(m => m.id == userMonster.monsterId);
                PMApiUtil.ErrorIf(monster == null, PMErrorCode.Unknown, "invalie monsterId");

                // モンスターをレベルアップ
                var afterStatus = MonsterUtil.GetMonsterStatus(monster, afterLevel);
                var customData  = new UserMonsterCustomData()
                {
                    level  = afterLevel,
                    exp    = afterExp,
                    hp     = afterStatus.hp,
                    attack = afterStatus.attack,
                    heal   = afterStatus.heal,
                    grade  = userMonster.customData.grade,
                };
                await DataProcessor.UpdateUserMonsterCustomDataAsync(context, userMonster.id, customData);

                // 経験値を消費
                await DataProcessor.ConsumeItemAsync(context, exp.id, request.exp);

                // 強化後のレベルを返す
                var response = new MonsterLevelUpApiResponse()
                {
                    level = afterLevel
                };
                return(PlayFabSimpleJson.SerializeObject(response));
            }catch (PMApiException e) {
                // レスポンスの作成
                var response = new PMApiResponseBase()
                {
                    errorCode = e.errorCode,
                    message   = e.message
                };
                return(PlayFabSimpleJson.SerializeObject(response));
            }
        }
    // 指定したモンスターのカスタムデータを更新
    public static async Task UpdateUserMonsterCustomDataAsync(FunctionExecutionContext <dynamic> context, string itemInstanceId, UserMonsterCustomData customData)
    {
        var serverApi = new PlayFabServerInstanceAPI(context.ApiSettings, context.AuthenticationContext);

        var customDataDict = UserDataUtil.GetCustomDataDict(customData);
        var result         = await serverApi.UpdateUserInventoryItemCustomDataAsync(new UpdateUserInventoryItemDataRequest()
        {
            PlayFabId      = context.CallerEntityProfile.Lineage.MasterPlayerAccountId,
            ItemInstanceId = itemInstanceId,
            Data           = customDataDict,
        });
    }