import os
import io
import sys
import asyncio
import discord
import aiohttp
import pandas as pd
import gradio as gr
import logging
from discord.ext import commands

# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Environment variable for Discord token
DISCORD_TOKEN = os.environ.get("DISCORD_TOKEN", None)
if not DISCORD_TOKEN:
    logger.error("DISCORD_TOKEN not set. Exiting.")
    sys.exit(1)

# Create Discord bot with all intents
intents = discord.Intents.all()
bot = commands.Bot(command_prefix="!", intents=intents)

async def process_row(row, guild, role):
    """
    Process a single CSV row: if the Discord member associated with the row hasn't received the role, add it.
    """
    hf_user_name = row["hf_user_name"]
    if pd.notna(hf_user_name) and hf_user_name.lower() != "n/a":
        discord_id = row["discord_user_id"].strip("L")
        try:
            member = guild.get_member(int(discord_id))
        except Exception as e:
            logger.error(f"Error converting Discord ID {discord_id}: {e}")
            return

        if not member:
            return

        if role not in member.roles:
            try:
                await member.add_roles(role)
                logger.info(f"Role added to member: {member}")
                lunar = bot.get_user(811235357663297546)
                if lunar:
                    await lunar.send(f"Verified role given to {member}!")
                await member.send(
                    f"Verification successful! [{member} <---> {row['discord_user_name']}]"
                )
            except Exception as e:
                logger.error(f"Error processing member {member}: {e}")

async def give_verified_roles():
    """
    Periodically fetch CSV data from Google Sheets and verify roles for members.
    """
    while True:
        try:
            async with aiohttp.ClientSession() as session:
                try:
                    async with session.get(
                        "https://docs.google.com/spreadsheets/d/1C8aLqgCqLYcMiIFf-P_Aosaa03C_WLIB_UyqvjSdWg8/export?format=csv&gid=0",
                        timeout=10,
                    ) as response:
                        if response.status != 200:
                            logger.error(f"Failed to fetch CSV: HTTP {response.status}")
                            await asyncio.sleep(30)
                            continue
                        csv_data = await response.text()
                        # Offload CSV parsing to avoid blocking the event loop.
                        global_df = await asyncio.to_thread(pd.read_csv, io.StringIO(csv_data))
                except asyncio.TimeoutError:
                    logger.error("CSV fetch timed out.")
                    await asyncio.sleep(30)
                    continue
                except Exception as e:
                    logger.error(f"Error fetching CSV: {e}")
                    await asyncio.sleep(30)
                    continue

            guild = bot.get_guild(879548962464493619)
            if not guild:
                logger.error("Guild not found.")
                await asyncio.sleep(30)
                continue
            role = guild.get_role(900063512829755413)
            if not role:
                logger.error("Role not found.")
                await asyncio.sleep(30)
                continue

            # Ensure all guild members are cached.
            await guild.chunk()

            tasks = [process_row(row, guild, role) for _, row in global_df.iterrows()]
            await asyncio.gather(*tasks)
        except Exception as e:
            logger.error(f"Error in give_verified_roles loop: {e}")
        await asyncio.sleep(30)  # Adjust the sleep interval as needed

@bot.event
async def on_ready():
    logger.info(f"We have logged in as {bot.user}")
    # Start the background role verification loop
    bot.loop.create_task(give_verified_roles())
    # Optionally, you can add a heartbeat task to log regular status messages.
    bot.loop.create_task(heartbeat())

async def heartbeat():
    """Simple heartbeat task to indicate the bot is still responsive."""
    while True:
        logger.info("Heartbeat: Bot is active.")
        await asyncio.sleep(60)

def greet(name):
    return "Hello " + name + "!"

# Create the Gradio interface
demo = gr.Interface(fn=greet, inputs="text", outputs="text")

async def main():
    # Launch Gradio in a separate thread to avoid blocking
    gradio_thread = asyncio.to_thread(demo.launch, share=False)
    await asyncio.gather(
        bot.start(DISCORD_TOKEN),
        gradio_thread
    )

if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        logger.info("Shutting down...")