"""Voice call management routes + helpers."""

import asyncio
from fastapi import APIRouter, Form
from fastapi.responses import JSONResponse
import discord
import globals
from utils.dm_logger import dm_logger
from utils.logger import get_logger

logger = get_logger('api')

router = APIRouter()


@router.post("/voice/call")
async def initiate_voice_call(user_id: str = Form(...), voice_channel_id: str = Form(...)):
    """
    Initiate a voice call to a user.

    Flow:
    1. Start STT and TTS containers
    2. Wait for models to load (health check)
    3. Join voice channel
    4. Send DM with invite to user
    5. Wait for user to join (30min timeout)
    6. Auto-disconnect 45s after user leaves
    """
    logger.info(f"📞 Voice call initiated for user {user_id} in channel {voice_channel_id}")

    # Check if bot is running
    if not globals.client or not globals.client.loop or not globals.client.loop.is_running():
        return JSONResponse(status_code=503, content={"success": False, "error": "Bot is not running"})

    # Run the voice call setup in the bot's event loop
    try:
        future = asyncio.run_coroutine_threadsafe(
            _initiate_voice_call_impl(user_id, voice_channel_id),
            globals.client.loop
        )
        result = future.result(timeout=90)  # 90 second timeout for container warmup
        return result
    except Exception as e:
        logger.error(f"Error initiating voice call: {e}", exc_info=True)
        return JSONResponse(status_code=500, content={"success": False, "error": str(e)})


async def _initiate_voice_call_impl(user_id: str, voice_channel_id: str):
    """Implementation of voice call initiation that runs in the bot's event loop."""
    from utils.container_manager import ContainerManager
    from utils.voice_manager import VoiceSessionManager

    try:
        # Convert string IDs to integers for Discord API
        user_id_int = int(user_id)
        channel_id_int = int(voice_channel_id)

        # Get user and channel
        user = await globals.client.fetch_user(user_id_int)
        if not user:
            return JSONResponse(status_code=404, content={"success": False, "error": "User not found"})

        channel = globals.client.get_channel(channel_id_int)
        if not channel or not isinstance(channel, discord.VoiceChannel):
            return JSONResponse(status_code=404, content={"success": False, "error": "Voice channel not found"})

        # Get a text channel for voice operations (use first text channel in guild)
        text_channel = None
        for ch in channel.guild.text_channels:
            if ch.permissions_for(channel.guild.me).send_messages:
                text_channel = ch
                break

        if not text_channel:
            return JSONResponse(status_code=404, content={"success": False, "error": "No accessible text channel found"})

        # Start containers
        logger.info("Starting voice containers...")
        containers_started = await ContainerManager.start_voice_containers()

        if not containers_started:
            return JSONResponse(status_code=500, content={"success": False, "error": "Failed to start voice containers"})

        # Start voice session
        logger.info(f"Starting voice session in {channel.name}")
        session_manager = VoiceSessionManager()

        try:
            await session_manager.start_session(channel.guild.id, channel, text_channel)
        except Exception as e:
            await ContainerManager.stop_voice_containers()
            return JSONResponse(status_code=500, content={"success": False, "error": f"Failed to start voice session: {str(e)}"})

        # Set up voice call tracking (use integer ID)
        session_manager.active_session.call_user_id = user_id_int

        # Generate invite link
        invite = await channel.create_invite(
            max_age=1800,  # 30 minutes
            max_uses=1,
            reason="Miku voice call"
        )

        # Send DM to user
        try:
            # Get LLM to generate a personalized invitation message
            from utils.llm import query_llama

            invitation_prompt = f"""You're calling {user.name} in voice chat! Generate a cute, excited message inviting them to join you. 
Keep it brief (1-2 sentences). Make it feel personal and enthusiastic!"""

            invitation_text = await query_llama(
                user_prompt=invitation_prompt,
                user_id=user.id,
                guild_id=None,
                response_type="voice_call_invite",
                author_name=user.name
            )

            dm_message = f"📞 **Miku is calling you! Very experimental! Speak clearly, loudly and close to the mic! Expect weirdness!** 📞\n\n{invitation_text}\n\n🎤 Join here: {invite.url}"

            sent_message = await user.send(dm_message)

            # Log to DM logger
            dm_logger.log_user_message(user, sent_message, is_bot_message=True)

            logger.info(f"✓ DM sent to {user.name}")

        except Exception as e:
            logger.error(f"Failed to send DM: {e}")
            # Don't fail the whole call if DM fails

        # Set up 30min timeout task
        session_manager.active_session.call_timeout_task = asyncio.create_task(
            _voice_call_timeout_handler(session_manager.active_session, user, channel)
        )

        return {
            "success": True,
            "user_id": user_id,
            "channel_id": voice_channel_id,
            "invite_url": invite.url
        }

    except Exception as e:
        logger.error(f"Error in voice call implementation: {e}", exc_info=True)
        return JSONResponse(status_code=500, content={"success": False, "error": str(e)})


async def _voice_call_timeout_handler(voice_session, user: discord.User, channel: discord.VoiceChannel):
    """Handle 30min timeout if user doesn't join."""
    try:
        await asyncio.sleep(1800)  # 30 minutes

        # Check if user ever joined
        if not voice_session.user_has_joined:
            logger.info(f"Voice call timeout - user {user.name} never joined")

            # End the session (which triggers cleanup)
            from utils.voice_manager import VoiceSessionManager
            session_manager = VoiceSessionManager()
            await session_manager.end_session()

            # Stop containers
            from utils.container_manager import ContainerManager
            await ContainerManager.stop_voice_containers()

            # Send timeout DM
            try:
                timeout_message = "Aww, I guess you couldn't make it to voice chat... Maybe next time! 💙"
                sent_message = await user.send(timeout_message)

                # Log to DM logger
                dm_logger.log_user_message(user, sent_message, is_bot_message=True)
            except Exception:
                pass

    except asyncio.CancelledError:
        # User joined in time, normal operation
        pass


@router.get("/voice/debug-mode")
def get_voice_debug_mode():
    """Get current voice debug mode status"""
    return {
        "debug_mode": globals.VOICE_DEBUG_MODE
    }


@router.post("/voice/debug-mode")
def set_voice_debug_mode(enabled: bool = Form(...)):
    """Set voice debug mode (shows transcriptions and responses in text channel)"""
    globals.VOICE_DEBUG_MODE = enabled
    logger.info(f"Voice debug mode set to: {enabled}")

    # Persist so it survives restarts
    try:
        from config_manager import config_manager
        config_manager.set("voice.debug_mode", enabled, persist=True)
    except Exception:
        pass

    return {
        "status": "ok",
        "debug_mode": enabled,
        "message": f"Voice debug mode {'enabled' if enabled else 'disabled'}"
    }
