"""Manual message sending routes + message reactions."""

import io
from typing import List
from fastapi import APIRouter, UploadFile, File, Form
from fastapi.responses import JSONResponse
import discord
import globals
from utils.logger import get_logger

logger = get_logger('api')

router = APIRouter()


@router.post("/manual/send")
async def manual_send(
    message: str = Form(...),
    channel_id: str = Form(...),
    files: List[UploadFile] = File(default=[]),
    reply_to_message_id: str = Form(None),
    mention_author: bool = Form(True)
):
    try:
        channel = globals.client.get_channel(int(channel_id))
        if not channel:
            return JSONResponse(status_code=404, content={"status": "error", "message": "Channel not found"})

        # Read file content immediately before the request closes
        file_data = []
        for file in files:
            try:
                file_content = await file.read()
                file_data.append({
                    'filename': file.filename,
                    'content': file_content
                })
            except Exception as e:
                logger.error(f"Failed to read file {file.filename}: {e}")
                return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to read file {file.filename}: {e}"})

        async def send_message_and_files():
            try:
                reference_message = None
                if reply_to_message_id:
                    try:
                        reference_message = await channel.fetch_message(int(reply_to_message_id))
                    except Exception as e:
                        logger.error(f"Could not fetch message {reply_to_message_id} for reply: {e}")
                        return

                if message.strip():
                    if reference_message:
                        await channel.send(message, reference=reference_message, mention_author=mention_author)
                        logger.info(f"Manual message sent as reply to #{channel.name}")
                    else:
                        await channel.send(message)
                        logger.info(f"Manual message sent to #{channel.name}")

                for file_info in file_data:
                    try:
                        await channel.send(file=discord.File(io.BytesIO(file_info['content']), filename=file_info['filename']))
                        logger.info(f"File {file_info['filename']} sent to #{channel.name}")
                    except Exception as e:
                        logger.error(f"Failed to send file {file_info['filename']}: {e}")

            except Exception as e:
                logger.error(f"Failed to send message: {e}")

        globals.client.loop.create_task(send_message_and_files())
        return {"status": "ok", "message": "Message and files queued for sending"}

    except Exception as e:
        return JSONResponse(status_code=500, content={"status": "error", "message": f"Error: {e}"})


@router.post("/manual/send-webhook")
async def manual_send_webhook(
    message: str = Form(...),
    channel_id: str = Form(...),
    persona: str = Form("miku"),
    files: List[UploadFile] = File(default=[]),
    reply_to_message_id: str = Form(None),
    mention_author: bool = Form(True)
):
    """Send a manual message via webhook as either Hatsune Miku or Evil Miku"""
    try:
        from utils.bipolar_mode import get_or_create_webhooks_for_channel, get_miku_display_name, get_evil_miku_display_name

        channel = globals.client.get_channel(int(channel_id))
        if not channel:
            return JSONResponse(status_code=404, content={"status": "error", "message": "Channel not found"})

        if persona not in ["miku", "evil"]:
            return JSONResponse(status_code=400, content={"status": "error", "message": "Invalid persona. Must be 'miku' or 'evil'"})

        file_data = []
        for file in files:
            try:
                file_content = await file.read()
                file_data.append({
                    'filename': file.filename,
                    'content': file_content
                })
            except Exception as e:
                logger.error(f"Failed to read file {file.filename}: {e}")
                return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to read file {file.filename}: {e}"})

        async def send_webhook_message():
            try:
                webhooks = await get_or_create_webhooks_for_channel(channel)
                if not webhooks:
                    logger.error(f"Failed to create webhooks for channel #{channel.name}")
                    return

                webhook = webhooks["evil_miku"] if persona == "evil" else webhooks["miku"]
                display_name = get_evil_miku_display_name() if persona == "evil" else get_miku_display_name()

                discord_files = []
                for file_info in file_data:
                    discord_files.append(discord.File(io.BytesIO(file_info['content']), filename=file_info['filename']))

                from utils.bipolar_mode import get_persona_avatar_urls
                avatar_urls = get_persona_avatar_urls()
                avatar_url = avatar_urls.get("evil_miku") if persona == "evil" else avatar_urls.get("miku")

                if discord_files:
                    await webhook.send(
                        content=message, username=display_name,
                        avatar_url=avatar_url, files=discord_files, wait=True
                    )
                else:
                    await webhook.send(
                        content=message, username=display_name,
                        avatar_url=avatar_url, wait=True
                    )

                persona_name = "Evil Miku" if persona == "evil" else "Hatsune Miku"
                logger.info(f"Manual webhook message sent as {persona_name} to #{channel.name}")

            except Exception as e:
                logger.error(f"Failed to send webhook message: {e}")
                import traceback
                traceback.print_exc()

        globals.client.loop.create_task(send_webhook_message())
        return {"status": "ok", "message": f"Webhook message queued for sending as {persona}"}

    except Exception as e:
        return JSONResponse(status_code=500, content={"status": "error", "message": f"Error: {e}"})


@router.post("/messages/react")
async def add_reaction_to_message(
    message_id: str = Form(...),
    channel_id: str = Form(...),
    emoji: str = Form(...)
):
    """Add a reaction to a specific message"""
    try:
        if not globals.client or not globals.client.loop or not globals.client.loop.is_running():
            return JSONResponse(status_code=503, content={"status": "error", "message": "Bot not ready"})

        try:
            msg_id = int(message_id)
            chan_id = int(channel_id)
        except ValueError:
            return JSONResponse(status_code=400, content={"status": "error", "message": "Invalid message ID or channel ID format"})

        channel = globals.client.get_channel(chan_id)
        if not channel:
            return JSONResponse(status_code=404, content={"status": "error", "message": f"Channel {channel_id} not found"})

        async def add_reaction_task():
            try:
                message = await channel.fetch_message(msg_id)
                await message.add_reaction(emoji)
                logger.info(f"Added reaction {emoji} to message {msg_id} in channel #{channel.name}")
            except discord.NotFound:
                logger.error(f"Message {msg_id} not found in channel #{channel.name}")
            except discord.Forbidden:
                logger.error(f"Bot doesn't have permission to add reactions in channel #{channel.name}")
            except discord.HTTPException as e:
                logger.error(f"Failed to add reaction: {e}")
            except Exception as e:
                logger.error(f"Unexpected error adding reaction: {e}")

        globals.client.loop.create_task(add_reaction_task())

        return {
            "status": "ok",
            "message": f"Reaction {emoji} queued for message {message_id}"
        }

    except Exception as e:
        logger.error(f"Failed to add reaction: {e}")
        return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to add reaction: {e}"})
