public async Task GiveTownAsync(
            [FromRoute] uint townId,
            [FromRoute] uint countryId)
        {
            ErrorCode.NotSupportedError.Throw();

            using (var repo = MainRepository.WithReadAndWrite())
            {
                var system = await repo.System.GetAsync();

                if (system.RuleSet == GameRuleSet.SimpleBattle)
                {
                    ErrorCode.RuleSetError.Throw();
                }

                var chara = await repo.Character.GetByIdAsync(this.AuthData.CharacterId).GetOrErrorAsync(ErrorCode.LoginCharacterNotFoundError);

                var myPosts = await repo.Country.GetCharacterPostsAsync(chara.Id);

                if (!myPosts.Any(p => p.Type.CanDiplomacy()))
                {
                    ErrorCode.NotPermissionError.Throw();
                }

                var country = await repo.Country.GetAliveByIdAsync(chara.CountryId).GetOrErrorAsync(ErrorCode.CountryNotFoundError);

                var targetTown = await repo.Town.GetByIdAsync(townId).GetOrErrorAsync(ErrorCode.TownNotFoundError);

                var targetCountry = await repo.Country.GetAliveByIdAsync(countryId).GetOrErrorAsync(ErrorCode.CountryNotFoundError);

                if (targetTown.CountryId != chara.CountryId)
                {
                    // 自分以外の国の都市を割譲できない
                    ErrorCode.InvalidOperationError.Throw();
                }

                if (targetCountry.AiType != CountryAiType.Human)
                {
                    // AI国家に割譲できない
                    ErrorCode.InvalidOperationError.Throw();
                }

                var allTowns = await repo.Town.GetAllAsync();

                if (!allTowns.GetAroundCountries(targetTown).Contains(countryId))
                {
                    // 割譲で飛び地は作れない
                    ErrorCode.InvalidOperationError.Throw();
                }

                var isSurrender = allTowns.Count(t => t.CountryId == chara.CountryId) == 1;

                // 割譲
                var defenders = (await repo.Town.GetAllDefendersAsync()).Where(d => d.TownId == townId);
                foreach (var d in defenders)
                {
                    repo.Town.RemoveDefender(d.CharacterId);
                    await StatusStreaming.Default.SendTownToAllAsync(ApiData.From(d), repo, targetTown);
                }
                targetTown.CountryId = targetCountry.Id;
                var townCharacters = await repo.Town.GetCharactersAsync(townId);

                foreach (var character in townCharacters)
                {
                    await CharacterService.StreamCharacterAsync(repo, character);
                }
                await StatusStreaming.Default.SendTownToAllAsync(ApiData.From(targetTown), repo);

                await AnonymousStreaming.Default.SendAllAsync(ApiData.From(new TownForAnonymous(targetTown)));

                await LogService.AddMapLogAsync(repo, true, EventType.Concession, $"<country>{country.Name}</country> は、<country>{targetCountry.Name}</country> に <town>{targetTown.Name}</town> を割譲しました");

                if (isSurrender)
                {
                    // 降伏
                    await CountryService.OverThrowAsync(repo, country, targetCountry);

                    await LogService.AddMapLogAsync(repo, true, EventType.Surrender, $"<country>{country.Name}</country> は、<country>{targetCountry.Name}</country> に降伏しました");
                }
            }
        }