import random
import discord
from discord.ext import tasks, commands
from discord import app_commands
import asyncpraw
from asyncio import sleep as async_sleep

from config_manager import ConfigManager
import cogs.views as views
import storybot_exceptions

# Listens for DMs to add to the story
class story_prompt_generator(commands.GroupCog, group_name='writing_prompt'):
    def __init__(self, bot: discord.Client):
        self.bot = bot
        self.config_manager : ConfigManager = bot.config_manager
        
        self.reddit_manager = asyncpraw.Reddit(
            client_id=self.config_manager.get_reddit_client_id(),
            client_secret=self.config_manager.get_reddit_client_secret(),
            
            username=self.config_manager.get_reddit_username(),
            password=self.config_manager.get_reddit_password(),
            
            user_agent="StoryBot Server"
        )
        

    async def cog_load(self) -> None:
        await super().cog_load()
        
        
        self.subreddits = {
            "WritingPrompts": {
                "condition": lambda x : x.title[:4] == "[WP]",
                },
            "SimplePrompts": {
                "condition": lambda x : True,
                }
        }
        
        for key in self.subreddits.keys():
            self.subreddits[key]["subreddit"] = await self.reddit_manager.subreddit(key)
            await self.subreddits[key]["subreddit"].load()
            
            self.subreddits[key]["list"] = []
        
    
    async def reset_random_prompts(self):
        """Refreshes the list of prompts from Reddit"""
        for key in self.subreddits.keys():
            try:
                new_submissions = []
                async for x in self.subreddits[key]["subreddit"].random_rising(limit=100):
                    try:
                        if (not x.over_18 and
                            self.subreddits[key]["condition"](x) and
                            not self.discord_generic.contains_profanity(x.title) and
                            not self.discord_generic.contains_profanity(x.author.name)):
                            
                            new_submissions.append(x)
                    except AttributeError:
                        pass
                
                await async_sleep(0) # Yield control of the event loop
                
                async for x in self.subreddits[key]["subreddit"].hot(limit=100):
                    try:
                        if (not x.over_18 and
                            self.subreddits[key]["condition"](x) and
                            not self.discord_generic.contains_profanity(x.title) and
                            not self.discord_generic.contains_profanity(x.author.name)):
                            
                            new_submissions.append(x)
                    except AttributeError:
                        pass
                    
                self.subreddits[key]["list"] = list(set(new_submissions))
                print(f"Loaded {len(self.subreddits[key]['list'])} prompts from r/{key}")
            except Exception as e:
                print(f"Error refreshing r/{key}: {e}. The list of r/{key} currently has {len(self.subreddits[key]['list'])} items.")
            
            await async_sleep(0) # Yield control of the event loop


    @tasks.loop(hours=4)
    async def new_reddit_prompts(self):
        await self.reset_random_prompts()
        
    @commands.Cog.listener()
    async def on_ready(self):
        loop_tasks = [
            self.new_reddit_prompts
        ]
        
        for task in loop_tasks:
            try:
                task.start()
            except RuntimeError as e:
                if not str(e) == "Task is already launched and is not completed.":
                    raise RuntimeError(str(e))

    def cog_unload(self):
        self.timeout_checker.cancel()
        
        
        
    @app_commands.checks.cooldown(1, 5) # The command can only be run once every 5 seconds
    @app_commands.command(name="reddit_specific")
    async def story_prompt(self, interaction: discord.Interaction, public: bool = True):
        """Returns a prompt from r/WritingPrompts. Note: I have no control over these

        Args:
            interaction (discord.Interaction): The default interaction
            public (bool, optional): Whether the response should be public. Defaults to True.
        """
        
        await self.reply_to_interaction(interaction=interaction, public=public, subreddit_name="WritingPrompts")

    @app_commands.checks.cooldown(1, 5) # The command can only be run once every 5 seconds
    @app_commands.command(name="reddit_vague")
    async def simple_story_prompt(self, interaction: discord.Interaction, public: bool = True):
        """Returns a vague writing prompt from r/SimplePrompts. Note: I have no control over these

        Args:
            interaction (discord.Interaction): The default interaction
            public (bool, optional): Whether the response should be public. Defaults to True.
        """
        
        await self.reply_to_interaction(interaction=interaction, public=public, subreddit_name="SimplePrompts")
          
          
          
          
    async def reply_to_interaction(self, interaction: discord.Interaction, public: bool, subreddit_name: str) -> None:
        try:
            await self.discord_generic.reply_to_message(reply_to=interaction, embed=await self.get_submission_embed(list_of_reddit_submissions = self.subreddits[subreddit_name]["list"]), ephemeral=not public)
        except storybot_exceptions.RedditSubmissionListIsEmpty:
            await self.discord_generic.reply_to_message(reply_to=interaction, content="The bot is currently refreshing its story prompts. Try again in a minute or two!", ephemeral=not public, error=True)



    async def get_submission_embed(self, list_of_reddit_submissions: list) -> discord.Embed:
        """Returns an embed for a random object in `list_of_reddit_submissions`

        Args:
            list_of_reddit_submissions (list): the list to choose a random submission from

        Raises:
            storybot_exceptions.RedditSubmissionListIsEmpty: the list passed is empty

        Returns:
            discord.Embed: the embed made based on the list
        """
        # TODO: specify list type in header
        
        if list_of_reddit_submissions == []:
            raise storybot_exceptions.RedditSubmissionListIsEmpty()
        
        submission = random.choice(list_of_reddit_submissions)
        
        author_name = submission.author.name.replace('_', '\_')
        if submission.title[:4] == "[WP]":
            post_title = submission.title[4:].strip()
        else:
            post_title = submission.title.strip()
        
        return await self.discord_generic.create_embed(
            content=post_title,
            title=f"Submitted to r/{submission.subreddit.display_name} by u/{author_name}",
            random_fact = False,
            footer = "Note - I try to filter these as best I can, but ultimately I am just grabbing random prompts from the internet. Use at your own risk!",
            url = submission.url,
            #author_icon_url = self.r_writingprompts.icon_img
        )

async def setup(bot):
    await bot.add_cog(story_prompt_generator(bot))
