import discord
from discord import app_commands
import os
import requests
import asyncio
import aiohttp  # Use aiohttp for asynchronous HTTP requests
import gradio as gr  # Import Gradio

# --- Environment Variables & Setup ---
DISCORD_BOT_TOKEN = os.getenv("DISCORD_BOT_TOKEN")
GLIF_API_TOKEN = os.getenv("GLIF_API_TOKEN0")
GLIF_API_URL = "https://simple-api.glif.app"
glif_token_id = 0
glif_tokens_tried = 0
no_of_accounts = 11
if not DISCORD_BOT_TOKEN or not GLIF_API_TOKEN:
    raise ValueError("Both DISCORD_BOT_TOKEN and GLIF_API_TOKEN must be set.")

# --- Discord Bot Setup ---
intents = discord.Intents.default()
client = discord.Client(intents=intents)
tree = app_commands.CommandTree(client)


async def generate_image_async(prompt, aspect_ratio, realism):
    global glif_token_id
    global GLIF_API_TOKEN
    global glif_tokens_tried
    global no_of_accounts
    payload = {
        "id": "cm3ugmzv2002gnckiosrwk6xi",
        "inputs": [prompt, aspect_ratio, str(realism).lower()],
    }
    headers = {"Authorization": f"Bearer {GLIF_API_TOKEN}"}

    async with aiohttp.ClientSession() as session:
        try:
            async with session.post(
                GLIF_API_URL, json=payload, headers=headers, timeout=15
            ) as response:
                response.raise_for_status()
                response_data = await response.json()
                if "error" in response_data:
                    if 'error 429' in response_data['error']:
                        if glif_tokens_tried<no_of_accounts:
                            glif_token_id = (glif_token_id+1)%no_of_accounts
                            glif_tokens_tried+=1
                            GLIF_API_TOKEN = os.getenv(f"GLIF_API_TOKEN{glif_token_id}")
                            response_data = await generate_image_async(prompt, aspect_ratio, realism)
                            glif_tokens_tried = 0
                            return response_data
                        response_data = "No credits available"
                    return response_data
                elif "output" in response_data:
                    return f"prompt:{response_data['inputs']['Prompt']}\noutput:{response_data['output']}"
                else:
                    return "Error: Unexpected response from server"

        except asyncio.TimeoutError:
            return "Error: API request timed out."
        except aiohttp.ClientError as e:
            return f"API request failed: {e}"
        except Exception as e:
            return f"Exception:{e}" 


@tree.command(name="generate", description="Generates an image based on a text prompt")
@app_commands.choices(
    aspect_ratio=[
        app_commands.Choice(name="1:1 (Square)", value="1:1"),
        app_commands.Choice(name="9:16 (Vertical)", value="9:16"),
        app_commands.Choice(name="16:9 (Horizontal)", value="16:9"),
        app_commands.Choice(name="3:4", value="3:4"),
        app_commands.Choice(name="4:3", value="4:3"),
        app_commands.Choice(name="9:21", value="9:21"),
        app_commands.Choice(name="21:9", value="21:9"),
    ]
)
async def generate_command(
    interaction: discord.Interaction,
    prompt: str,
    aspect_ratio: app_commands.Choice[str],
    realism:bool,
):
    try:
        await interaction.response.defer()

        image_url_or_error = await generate_image_async(prompt, aspect_ratio.value, realism)
        # await interaction.response.send_message(f"Error:{image_url_or_error}")
        if image_url_or_error:
        # if image_url_or_error.startswith("http"):
            await interaction.followup.send(
                # f"Here's your generated image based on the prompt '{prompt}' with aspect ratio {aspect_ratio.name}:\n{image_url_or_error}"
                f"{image_url_or_error}"
            )
        else:
            await interaction.followup.send(
                f"Sorry, I couldn't generate an image"
            )
    except Exception as e:
        await interaction.followup.send(f"Error")


@tree.command(name="hello", description="Says hello!")
async def hello_command(interaction):
    await interaction.response.send_message("Hello there!")


async def on_ready():
    await tree.sync()
    print("Bot is ready!")


client.event(on_ready)


# --- Gradio Interface ---
def echo_text(text):
    return text


def run_gradio():
    gr.Interface(
        fn=echo_text,
        inputs="text",
        outputs="text",
        live=False,
        title="Minimal Gradio Interface",
    ).launch(server_name="0.0.0.0", server_port=7860, share=False, show_error=True)


# --- Main ---
async def main():
    bot_task = asyncio.create_task(client.start(DISCORD_BOT_TOKEN))
    gradio_task = asyncio.to_thread(run_gradio)

    await asyncio.gather(bot_task, gradio_task)


if __name__ == "__main__":
    asyncio.run(main())