from twitchio.ext import commands
import os
from dotenv import load_dotenv
import threading
import asyncio
import streamlit as st
import datetime

load_dotenv()

TAG_INDICATOR_CHAR = "#"
MAX_NUM_TAGS_TO_SEND = 5
TAG_SEND_INTERVAL = 30

NUM_LEADERBOARD_TAGS = 10


class SongBot(commands.Bot):
    def __init__(self):
        # Get token from environment variable
        token = os.getenv("TWITCH_TOKEN")
        if not token:
            raise ValueError("TWITCH_TOKEN environment variable is not set")

        # Bot configuration
        super().__init__(
            token=token,
            prefix="!",
            initial_channels=["djsuno"],  # Channel to join
        )

        # Song list to store requests
        self.pending_tags = {}
        self.sent_tag_history = []

    async def event_ready(self):
        """Called when the bot is ready"""
        print(f"Bot is ready! Logged in as {self.nick}")
        print(f"Connected to channels: {self.connected_channels}")

    async def event_message(self, message):
        """Called for every message in chat"""
        # Ignore messages from the bot itself
        if message.echo:
            return

        # Print all messages for debugging (optional)
        print(f"{message.author.name}: {message.content}")

        if message.content.startswith(TAG_INDICATOR_CHAR):
            new_tag = message.content[1:]
            if not new_tag:
                return
            if new_tag not in self.pending_tags:
                self.pending_tags[new_tag] = 0
            self.pending_tags[new_tag] += 1
            print(f"Current tags: {self.pending_tags}")
            await message.channel.send(f"Added tag: {new_tag}")

    def get_and_reset_tags(self):
        print(f"Getting {MAX_NUM_TAGS_TO_SEND} most requested tags...")
        if len(self.pending_tags) < MAX_NUM_TAGS_TO_SEND:
            tags_to_send = list(self.pending_tags.keys())
        else:
            tags_to_send = []
            for i in range(MAX_NUM_TAGS_TO_SEND):
                max_count_tag = None
                max_count = 0
                for tag in self.pending_tags:
                    if tag not in tags_to_send and self.pending_tags[tag] > max_count:
                        max_count = self.pending_tags[tag]
                        max_count_tag = tag
                tags_to_send.append(max_count_tag)

        print(f"Tags to send: {tags_to_send}")

        self.sent_tag_history.append(tags_to_send[:])
        self.pending_tags = {}
        print("Pending tags has been reset.")
        return tags_to_send

    def write_to_streamlit(self, string):
        print(f"Printed to Streamlit: {string}")
        st.write(string)


def thread_main(thing1):
    asyncio.run(async_thread_main(thing1))


async def async_thread_main(thing1):
    bot = SongBot()
    thing1.append(bot)
    await bot.start()


async def main():
    thing1 = []
    threading.Thread(target=thread_main, daemon=True, args=(thing1,)).start()
    st.write("# LET'S A-GOOOOO!")
    col1, col2 = st.columns(2)

    tags = col1.empty()
    tag_history = col1.empty()
    instructions = col2.empty()
    pending_tags_leaderboard = col2.empty()

    instructions.markdown(
        f"""
**Welcome to the greatest unending playlist in existence!**
* Control the style of the music by sending tags in chat.
* Send a tag by typing #TAGNAME in chat! For example: #pop, #rock, #happy, #kawaii future bass, #metal, etc.
* Every {TAG_SEND_INTERVAL} seconds, the top {MAX_NUM_TAGS_TO_SEND} most requested tags will be sent to Suno and used to continue the song.
* Sit back and enjoy the music!
"""
    )

    timestamp = datetime.datetime.now()
    timestamp2 = datetime.datetime.now()
    while True:
        # Send top 5 tags on a time interval
        if datetime.datetime.now() - timestamp > datetime.timedelta(
            seconds=TAG_SEND_INTERVAL
        ):
            assert len(thing1) > 0  # makes sure our bot exists

            # TODO: this is where we should send the tags to backend
            sent_tags = thing1[0].get_and_reset_tags()

            tags_joined = f"{', '.join(sent_tags)}"
            if not tags_joined:
                tags_joined = "(no tags sent)"
            tags.markdown(
                f"**Most recent {MAX_NUM_TAGS_TO_SEND} tags sent:** {tags_joined}"
            )
            if len(thing1[0].sent_tag_history) > 1:
                tag_history_str = ""
                for tag_list in thing1[0].sent_tag_history[-2::-1]:
                    tags_joined = f"{', '.join(tag_list)}"
                    if not tags_joined:
                        tags_joined = "(no tags sent)"
                    tag_history_str += f"{tags_joined}  \n"
                tag_history.markdown(f"**History:**  \n {tag_history_str.strip()}")
            timestamp = datetime.datetime.now()

        # Update leaderboard every second
        elif datetime.datetime.now() - timestamp2 > datetime.timedelta(seconds=1):
            leaderboard_tags = []
            leaderboard_counts = []
            for i in range(min(NUM_LEADERBOARD_TAGS, len(thing1[0].pending_tags))):
                max_count_tag = None
                max_count = 0
                for tag in thing1[0].pending_tags:
                    if (
                        tag not in leaderboard_tags
                        and thing1[0].pending_tags[tag] > max_count
                    ):
                        max_count = thing1[0].pending_tags[tag]
                        max_count_tag = tag
                leaderboard_tags.append(max_count_tag)
                leaderboard_counts.append(max_count)

            leaderboard_str = ""
            for i in range(len(leaderboard_tags)):
                leaderboard_str += (
                    f"{leaderboard_tags[i]} ({leaderboard_counts[i]} votes)  \n"
                )

            if not leaderboard_str:
                leaderboard_str = "(no tags requested yet)"

            pending_tags_leaderboard.markdown(
                f"**Top {NUM_LEADERBOARD_TAGS} tags:**  \n {leaderboard_str.strip()}"
            )

            timestamp2 = datetime.datetime.now()


# Run the bot
if __name__ == "__main__":
    # bot = SongBot()

    # threading.Thread(target=thread_main, daemon=True, args=(bot,)).start()

    # asyncio.run(bot.start())
    asyncio.run(main())
