Here's the start of an algorithm but you'll have to test it and make adjustments. We'll assume that you're using a good random # generator that truly generates arbitrary values.
Let's assume that we're building for the silver pack and that you said 1 in 50 are silver and 1 in 1000 are gold. Normalize to 1000 so 20 in 1000 are silver, 1 in 1000 are gold and the remaining are bronze. Generate a random number between 1 and 1000. You can partition your cards up as much as you want but somehow you'll need to decide where the 20 silver and 1 gold card sit in the 1-1000 range. Suppose, for example, that you specify that the gold card is at 1000 and the silver are 1-20. If the random # is in either range then you use that value. However I think you'll find that 1 in 1000 is extremely rare even on the best days.
There are quite a few variants you can use to adjust the behavior to your liking such as pre-selecting the cards and randomizing from there or using some custom rules such as a gold pack always having at least 1 gold card.
Amazingly, it returns a random card. I'll look into the GetAllItemsAsync part and see how I can filter it based on what pack the user bought. If a gold pack is bought, I want to include all cards that are Bronze, Silver or Gold but only have a random 1 in a 100 shot at getting a gold card out of the pack.