public async Task ProcessPokemonSubscription(PokemonData pkmn)
        {
            if (!MasterFile.Instance.Pokedex.ContainsKey(pkmn.Id))
            {
                return;
            }

            var loc = _whm.GetGeofence(pkmn.Latitude, pkmn.Longitude);

            if (loc == null)
            {
                //_logger.Warn($"Failed to lookup city from coordinates {pkmn.Latitude},{pkmn.Longitude} {db.Pokemon[pkmn.Id].Name} {pkmn.IV}, skipping...");
                return;
            }

            var subscriptions = Manager.GetUserSubscriptionsByPokemonId(pkmn.Id);

            if (subscriptions == null)
            {
                _logger.Warn($"Failed to get subscriptions from database table.");
                return;
            }

            SubscriptionObject  user;
            PokemonSubscription subscribedPokemon;
            DiscordMember       member = null;
            var pokemon       = MasterFile.GetPokemon(pkmn.Id, pkmn.FormId);
            var matchesIV     = false;
            var matchesLvl    = false;
            var matchesGender = false;
            var matchesIVList = false;

            for (var i = 0; i < subscriptions.Count; i++)
            {
                try
                {
                    user = subscriptions[i];
                    if (user == null)
                    {
                        continue;
                    }

                    if (!user.Enabled)
                    {
                        continue;
                    }

                    if (!_whConfig.Servers.ContainsKey(user.GuildId))
                    {
                        continue;
                    }

                    if (!_whConfig.Servers[user.GuildId].EnableSubscriptions)
                    {
                        continue;
                    }

                    if (!_servers.ContainsKey(user.GuildId))
                    {
                        continue;
                    }

                    var client = _servers[user.GuildId];

                    try
                    {
                        member = await client.GetMemberById(user.GuildId, user.UserId);
                    }
                    catch (Exception ex)
                    {
                        _logger.Debug($"FAILED TO GET MEMBER BY ID {user.UserId}");
                        _logger.Error(ex);
                        continue;
                    }

                    if (!member.HasSupporterRole(_whConfig.Servers[user.GuildId].DonorRoleIds))
                    {
                        _logger.Debug($"User {member?.Username} ({user.UserId}) is not a supporter, skipping pokemon {pokemon.Name}...");
                        continue;
                    }

                    if (member?.Roles == null || loc == null)
                    {
                        continue;
                    }

                    if (!member.Roles.Select(x => x?.Name?.ToLower()).Contains(loc?.Name?.ToLower()))
                    {
                        //_logger.Info($"User {member.Username} does not have city role {loc.Name}, skipping pokemon {pokemon.Name}.");
                        continue;
                    }

                    /*
                     * var exists = user.Pokemon.Exists(x => string.IsNullOrEmpty(x.City) || (!string.IsNullOrEmpty(x.City) && string.Compare(loc.Name, x.City, true) == 0));
                     * if (!exists)
                     * {
                     *  //_logger.Debug($"Skipping notification for user {member.DisplayName} ({member.Id}) for Pokemon {pokemon.PokemonId} because the Pokemon is in city '{loc.Name}'.");
                     *  continue;
                     * }
                     */

                    // Only check distance if user has it set
                    if (user.DistanceM > 0)
                    {
                        var distance = new Coordinates(user.Latitude, user.Longitude).DistanceTo(new Coordinates(pkmn.Latitude, pkmn.Longitude));
                        if (user.DistanceM < distance)
                        {
                            //Skip if distance is set and is not with specified distance.
                            _logger.Debug($"Skipping notification for user {member.DisplayName} ({member.Id}) for Pokemon {pokemon.Name}, Pokemon is farther than set distance of '{user.DistanceM} meters.");
                            continue;
                        }
                    }

                    var form = Translator.Instance.GetFormName(pkmn.FormId);
                    subscribedPokemon = user.Pokemon.FirstOrDefault(x =>
                                                                    x.PokemonId == pkmn.Id &&
                                                                    (string.IsNullOrEmpty(x.Form) || string.Compare(x.Form, form, true) == 0) &&
                                                                    (string.IsNullOrEmpty(x.City) || (!string.IsNullOrEmpty(x.City) && string.Compare(loc.Name, x.City, true) == 0))
                                                                    );
                    if (subscribedPokemon == null)
                    {
                        //_logger.Info($"User {member.Username} not subscribed to Pokemon {pokemon.Name} (Form: {form}).");
                        continue;
                    }

                    matchesIV = Filters.MatchesIV(pkmn.IV, subscribedPokemon.MinimumIV);
                    //var matchesCP = _whm.Filters.MatchesCpFilter(pkmn.CP, subscribedPokemon.MinimumCP);
                    matchesLvl    = Filters.MatchesLvl(pkmn.Level, (uint)subscribedPokemon.MinimumLevel, (uint)subscribedPokemon.MaximumLevel);
                    matchesGender = Filters.MatchesGender(pkmn.Gender, subscribedPokemon.Gender);
                    matchesIVList = subscribedPokemon.IVList?.Contains($"{pkmn.Attack}/{pkmn.Defense}/{pkmn.Stamina}") ?? false;

                    if (!(
                            (/*!subscribedPokemon.HasStats && */ matchesIV && matchesLvl && matchesGender) ||
                            (subscribedPokemon.HasStats && matchesIVList)
                            ))
                    {
                        continue;
                    }

                    var embed = await pkmn.GeneratePokemonMessage(user.GuildId, client, _whConfig, null, loc.Name);

                    foreach (var emb in embed.Embeds)
                    {
                        _queue.Enqueue(new NotificationItem(user, member, emb, pokemon.Name, loc.Name, pkmn));
                    }

                    Statistics.Instance.SubscriptionPokemonSent++;
                    Thread.Sleep(5);
                }
                catch (Exception ex)
                {
                    _logger.Error(ex);
                }
            }

            subscriptions.Clear();
            subscriptions = null;
            member        = null;
            user          = null;
            loc           = null;
            pokemon       = null;

            await Task.CompletedTask;
        }
        public async Task ProcessPokemonSubscription(PokemonData pkmn)
        {
            if (!MasterFile.Instance.Pokedex.ContainsKey(pkmn.Id))
            {
                return;
            }

            // Cache the result per-guild so that geospatial stuff isn't queried for every single subscription below
            Dictionary <ulong, GeofenceItem> locationCache = new Dictionary <ulong, GeofenceItem>();

            GeofenceItem GetGeofence(ulong guildId)
            {
                if (!locationCache.TryGetValue(guildId, out var geofence))
                {
                    geofence = _whm.GetGeofence(guildId, pkmn.Latitude, pkmn.Longitude);
                    locationCache.Add(guildId, geofence);
                }

                return(geofence);
            }

            var subscriptions = Manager.GetUserSubscriptionsByPokemonId(pkmn.Id);

            if (subscriptions == null)
            {
                _logger.Warn($"Failed to get subscriptions from database table.");
                return;
            }

            SubscriptionObject  user;
            PokemonSubscription subscribedPokemon;
            DiscordMember       member = null;
            var pokemon       = MasterFile.GetPokemon(pkmn.Id, pkmn.FormId);
            var matchesIV     = false;
            var matchesLvl    = false;
            var matchesGender = false;
            var matchesIVList = false;

            for (var i = 0; i < subscriptions.Count; i++)
            {
                //var start = DateTime.Now;
                try
                {
                    user = subscriptions[i];
                    if (user == null)
                    {
                        continue;
                    }

                    if (!user.Enabled)
                    {
                        continue;
                    }

                    if (!_whConfig.Instance.Servers.ContainsKey(user.GuildId))
                    {
                        continue;
                    }

                    if (!_whConfig.Instance.Servers[user.GuildId].Subscriptions.Enabled)
                    {
                        continue;
                    }

                    if (!_servers.ContainsKey(user.GuildId))
                    {
                        continue;
                    }

                    var client = _servers[user.GuildId];

                    try
                    {
                        member = await client.GetMemberById(user.GuildId, user.UserId);
                    }
                    catch (Exception ex)
                    {
                        _logger.Debug($"FAILED TO GET MEMBER BY ID {user.UserId}");
                        _logger.Error(ex);
                        continue;
                    }

                    if (member?.Roles == null)
                    {
                        continue;
                    }

                    if (!member.HasSupporterRole(_whConfig.Instance.Servers[user.GuildId].DonorRoleIds))
                    {
                        _logger.Debug($"User {member?.Username} ({user.UserId}) is not a supporter, skipping pokemon {pokemon.Name}...");
                        // Automatically disable users subscriptions if not supporter to prevent issues
                        //user.Enabled = false;
                        //user.Save(false);
                        continue;
                    }

                    var form = Translator.Instance.GetFormName(pkmn.FormId);
                    subscribedPokemon = user.Pokemon.FirstOrDefault(x =>
                                                                    x.PokemonId == pkmn.Id &&
                                                                    (string.IsNullOrEmpty(x.Form) || (!string.IsNullOrEmpty(x.Form) && string.Compare(x.Form, form, true) == 0))
                                                                    );
                    // Not subscribed to Pokemon
                    if (subscribedPokemon == null)
                    {
                        //_logger.Debug($"User {member.Username} not subscribed to Pokemon {pokemon.Name} (Form: {form}).");
                        continue;
                    }

                    matchesIV = Filters.MatchesIV(pkmn.IV, subscribedPokemon.MinimumIV);
                    //var matchesCP = _whm.Filters.MatchesCpFilter(pkmn.CP, subscribedPokemon.MinimumCP);
                    matchesLvl    = Filters.MatchesLvl(pkmn.Level, (uint)subscribedPokemon.MinimumLevel, (uint)subscribedPokemon.MaximumLevel);
                    matchesGender = Filters.MatchesGender(pkmn.Gender, subscribedPokemon.Gender);
                    matchesIVList = subscribedPokemon.IVList?.Contains($"{pkmn.Attack}/{pkmn.Defense}/{pkmn.Stamina}") ?? false;

                    if (!(
                            (!subscribedPokemon.HasStats && matchesIV && matchesLvl && matchesGender) ||
                            (subscribedPokemon.HasStats && matchesIVList)
                            ))
                    {
                        continue;
                    }

                    var geofence = GetGeofence(user.GuildId);
                    if (geofence == null)
                    {
                        //_logger.Warn($"Failed to lookup city from coordinates {pkmn.Latitude},{pkmn.Longitude} {db.Pokemon[pkmn.Id].Name} {pkmn.IV}, skipping...");
                        continue;
                    }

                    var distanceMatches = user.DistanceM > 0 && user.DistanceM > new Coordinates(user.Latitude, user.Longitude).DistanceTo(new Coordinates(pkmn.Latitude, pkmn.Longitude));
                    var geofenceMatches = subscribedPokemon.Areas.Select(x => x.ToLower()).Contains(geofence.Name.ToLower());

                    // If set distance does not match and no geofences match, then skip Pokemon...
                    if (!distanceMatches && !geofenceMatches)
                    {
                        continue;
                    }

                    var embed = pkmn.GeneratePokemonMessage(user.GuildId, client, _whConfig.Instance, null, geofence.Name);
                    //var end = DateTime.Now.Subtract(start);
                    //_logger.Debug($"Took {end} to process Pokemon subscription for user {user.UserId}");
                    embed.Embeds.ForEach(x => _queue.Enqueue(new NotificationItem(user, member, x, pokemon.Name, geofence.Name, pkmn)));

                    Statistics.Instance.SubscriptionPokemonSent++;
                    Thread.Sleep(5);
                }
                catch (Exception ex)
                {
                    _logger.Error(ex);
                }
            }

            subscriptions.Clear();
            subscriptions = null;
            member        = null;
            user          = null;
            pokemon       = null;

            await Task.CompletedTask;
        }