import random, re
from ..core import command

die_pattern = re.compile(r'(?:(\d+)x)?(?:(\d+)d)?(\d+)?')
die_defaults = (1, 1, 6)
card_suits = ['hearts', 'diamonds', 'clubs', 'spades']
card_ranks = ['ace'] + list(range(2, 11)) + ['jack', 'queen', 'king']

class Random(metaclass=command.Cog):
	@command.command()
	async def dice(self, ctx, *args):
		"""Roll some dice, in `{rolls}x{dice}d{sides}` format. `{dice}` `{sides}`-sided dice are rolled and summed, `{rolls}` times."""
		results = []
		if not args: args = ('%dx%dd%d' % die_defaults,)
		for die in args:
			match = die_pattern.match(die)
			if match.group(0):
				rolls, dice, sides = (int(arg) if arg else default for arg, default in zip(match.groups(), die_defaults)) # Unpack with defaults
				results.append([sum(random.randint(1, sides) for _ in range(dice)) for _ in range(rolls)]) # Sum {dice} {sides}-sided die, {rolls} times
			else:
				return await ctx.send('BAKA! `{}` is not a valid dice pattern!', die)
		return await ctx.send('{}', '; '.join(', '.join(map(str, result)) for result in results))
	
	dice.example_usage = """
	`{prefix}dice` - roll a six-sided die
	`{prefix}dice 2d10` - roll two ten-sided dice and sum their results
	`{prefix}dice 10x20` - roll ten twenty-sided dice and report their results individually
	`{prefix}dice 4x2d12` - roll four pairs of twelve-sided dice and sum the result of each pair (produces four numbers between 2 and 24 inclusive)
	"""
	
	@command.command()
	async def choice(self, ctx, *choices):
		"""Pick randomly from the choices provided.
		All choices are weighted evenly. Include a choice multiple times to increase its weight."""
		await ctx.send('{}', random.choice(choices))
	
	choice.example_usage = """
	`{prefix}choice apple orange banana` - pick a fruit from the options given, with 1/3 probability for each
	`{prefix}choice apple apple orange banana banana banana` - pick a fruit, with 1/3 chance for apple, 1/6 chance for orange, and 1/2 chance for banana
	`{prefix}choice "apple orange" banana` - pick from "apple orange" and "banana", with even (50%) probability for each
	"""
	
	@command.command()
	async def choices(self, ctx, qty : int, *choices):
		"""Pick `{qty}` times from the choices provided, with replacement."""
		await ctx.send('{}', ', '.join(random.choices(choices, k=qty)))
	
	choices.example_usage = """
	`{prefix}choices 2 apple orange banana` - pick two fruits (with duplicates) from the options given, with 1/3 probability for each
	`{prefix}choices 12 apple apple orange banana banana banana` - pick a dozen fruit, with 1/3 chance for apple, 1/6 chance for orange, and 1/2 chance for banana
	`{prefix}choices 5 "apple orange" banana` - pick five tiems from "apple orange" and "banana", with even (50%) probability for each
	"""
	
	@command.command()
	async def sample(self, ctx, qty : int, *choices):
		"""Pick `{qty}` times from the choices provided, without replacement."""
		count, remainder = divmod(qty, len(choices)) # Number of times through the choices, and number of choices afterward
		results = []
		for _ in range(count):
			results.extend(random.sample(choices, k=len(choices)))
		if remainder:
			results.extend(random.sample(choices, k=remainder))
		await ctx.send('{}', ', '.join(results))
	
	sample.example_usage = """
	`{prefix}choices 2 apple orange banana` - pick two fruits (without duplicates) from the options given, with 1/3 probability for each
	`{prefix}choices 12 apple apple orange banana banana banana` - pick a dozen fruit, with 1/3 chance for apple, 1/6 chance for orange, and 1/2 chance for banana. The results will contain four apples, two oranges, and six bananas, in randomized order.
	`{prefix}choices 5 "apple orange" banana` - pick five tiems from "apple orange" and "banana", with even (50%) probability for each. The first four will be two "apple orange" and two "banana" in randomized order, and the last will be picked randomly.
	"""
	
	@command.command()
	async def card(self, ctx, qty : int = 1):
		"""Pick one or more cards from a 52-card deck.
		Multiple picks are done with replacement."""
		await ctx.send('{}', ', '.join('{} of {}'.format(random.choice(card_ranks), random.choice(card_suits)) for _ in range(qty)))
	
	card.example_usage = """
	`{prefix}card` - pick a random card
	`{prefix}card 6` - picks six random cards with replacement
	"""
