import discord
import aiohttp
import asyncio
import random
import string
import datetime
import os
import threading
import uvicorn
import logging
import sys
from api import app

from command_router import handle_command
from utils.scheduled import (
    schedule_random_bedtime,
    send_bedtime_reminder,
    send_monday_video
)
from utils.image_handling import (
    download_and_encode_image,
    analyze_image_with_qwen,
    rephrase_as_miku
)
from utils.core import (
    is_miku_addressed,
)
from utils.moods import (
    detect_mood_shift,
    set_sleep_state,
    nickname_mood_emoji,
    rotate_mood,
    load_mood_description,
    clear_angry_mood_after_delay
)
from utils.media import overlay_username_with_ffmpeg
from utils.kindness import detect_and_react_to_kindness
from utils.llm import query_ollama
from utils.autonomous import setup_autonomous_speaking, load_last_sent_tweets

import globals

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s: %(message)s",
    handlers=[
        logging.FileHandler("bot.log", mode='a', encoding='utf-8'),
        logging.StreamHandler(sys.stdout)  # Optional: see logs in stdout too
    ],
    force=True  # Override previous configs
)

@globals.client.event
async def on_ready():
    print(f'🎤 MikuBot connected as {globals.client.user}')

    globals.BOT_USER = globals.client.user

    # Change mood every 1 hour
    rotate_mood.start()

    # Schedule the weekly task (Monday 07:30)
    globals.scheduler.add_job(send_monday_video, 'cron', day_of_week='mon', hour=4, minute=30)

    # Schedule first bedtime reminder
    schedule_random_bedtime()
    # Reschedule every midnight
    globals.scheduler.add_job(schedule_random_bedtime, 'cron', hour=21, minute=0)
    #scheduler.add_job(send_bedtime_reminder, 'cron', hour=12, minute=22)i

    # Schedule autonomous speaking
    setup_autonomous_speaking()
    load_last_sent_tweets()

    globals.scheduler.start()

@globals.client.event
async def on_message(message):
    if message.author == globals.client.user:
        return

    handled, globals.CURRENT_MOOD_NAME, globals.CURRENT_MOOD, globals.PREVIOUS_MOOD_NAME, globals.IS_SLEEPING = await handle_command(
        message,
        set_sleep_state
    )

    if message.content.strip().lower() == "miku, rape this nigga balls" and message.reference:
        async with message.channel.typing():
            # Get replied-to user
            try:
                replied_msg = await message.channel.fetch_message(message.reference.message_id)
                target_username = replied_msg.author.display_name

                # Prepare video
                base_video = "MikuMikuBeam.mp4"
                output_video = f"/tmp/video_{''.join(random.choices(string.ascii_letters, k=5))}.mp4"

                await overlay_username_with_ffmpeg(base_video, output_video, target_username)

                caption = f"Here you go, @{target_username}! 🌟"
                #await message.channel.send(content=caption, file=discord.File(output_video))
                await replied_msg.reply(file=discord.File(output_video))

            except Exception as e:
                print(f"⚠️ Error processing video: {e}")
                await message.channel.send("Sorry, something went wrong while generating the video.")
            return

    text = message.content.strip()

    if await is_miku_addressed(message):

        if globals.IS_SLEEPING:
            # Initialize sleepy response count if not set yet
            if globals.SLEEPY_RESPONSES_LEFT is None:
                globals.SLEEPY_RESPONSES_LEFT = random.randint(3, 5)
                print(f"🎲 Sleepy responses allowed: {globals.SLEEPY_RESPONSES_LEFT}")

            if globals.SLEEPY_RESPONSES_LEFT > 0:
                if random.random() < 1/3:  # ⅓ chance
                    sleep_talk_lines = [
                        "mnnn... five more minutes... zzz...",
                        "nya... d-don't tickle me there... mm~",
                        "zz... nyaa~ pancakes flying... eep...",
                        "so warm... stay close... zzz...",
                        "huh...? is it morning...? nooo... \*rolls over*",
                        "\*mumbles* pink clouds... and pudding... heehee...",
                        "\*softly snores* zzz... nyuu... mmh..."
                    ]
                    response = random.choice(sleep_talk_lines)
                    await message.channel.typing()
                    await asyncio.sleep(random.uniform(1.5, 3.0))  # random delay before replying
                    await message.channel.send(response)
                    globals.SLEEPY_RESPONSES_LEFT -= 1
                    print(f"💤 Sleepy responses left: {globals.SLEEPY_RESPONSES_LEFT}")
                else:
                    # No response at all
                    print("😴 Miku is asleep and didn't respond.")
                return  # Skip any further message handling
            else:
                # Exceeded sleepy response count — wake up angry now!
                globals.IS_SLEEPING = False
                globals.CURRENT_MOOD_NAME = "angry"
                globals.CURRENT_MOOD = load_mood_description("angry")
                globals.SLEEPY_RESPONSES_LEFT = None

                # Set angry period end time 40 minutes from now
                globals.FORCED_ANGRY_UNTIL = datetime.datetime.utcnow() + datetime.timedelta(minutes=40)

                # Cancel any existing angry timer task first
                if globals.ANGRY_WAKEUP_TIMER and not globals.ANGRY_WAKEUP_TIMER.done():
                    globals.ANGRY_WAKEUP_TIMER.cancel()

                # Start cooldown task to clear angry mood after 40 mins
                globals.ANGRY_WAKEUP_TIMER = asyncio.create_task(clear_angry_mood_after_delay())

                print("😡 Miku woke up angry and will stay angry for 40 minutes!")

                globals.JUST_WOKEN_UP = True  # Set flag for next response
                
                await nickname_mood_emoji()
                await set_sleep_state(False)

                # Immediately get an angry response to send back
                try:
                    async with message.channel.typing():
                        angry_response = await query_ollama("...", user_id=str(message.author.id))
                        await message.channel.send(angry_response)
                finally:
                    # Reset the flag after sending the angry response
                    globals.JUST_WOKEN_UP = False

                return
 
        prompt = text  # No cleanup — keep it raw 
        user_id = str(message.author.id)
        
        # 1st kindness check with just keywords
        if globals.CURRENT_MOOD not in ["angry", "irritated"]:
            await detect_and_react_to_kindness(message)

        # Add replied Miku message to conversation history as context
        if message.reference:
            try:
                replied_msg = await message.channel.fetch_message(message.reference.message_id)
                if replied_msg.author == globals.client.user:
                    history = globals.conversation_history.get(user_id, [])
                    if not history or (history and history[-1][1] != replied_msg.content):
                        globals.conversation_history.setdefault(user_id, []).append(("", replied_msg.content))
            except Exception as e:
                print(f"⚠️ Failed to fetch replied message for context: {e}")

        async with message.channel.typing():
            # If message has an image attachment
            if message.attachments:
                for attachment in message.attachments:
                    if any(attachment.filename.lower().endswith(ext) for ext in [".jpg", ".jpeg", ".png", ".webp"]):

                        base64_img = await download_and_encode_image(attachment.url)
                        if not base64_img:
                            await message.channel.send("I couldn't load the image, sorry!")
                            return
					# Analyze image (objective description)
                    qwen_description = await analyze_image_with_qwen(base64_img)
                    miku_reply = await rephrase_as_miku(qwen_description, prompt)
                    
                    await message.channel.send(miku_reply)
                    return

            # If message is just a prompt, no image
            response = await query_ollama(prompt, user_id=str(message.author.id))
            
            await message.channel.send(response)
            
        # 2nd kindness check (only if no keywords detected)
        if globals.CURRENT_MOOD not in ["angry", "irritated"]:
            await detect_and_react_to_kindness(message, after_reply=True)

    # Manual Monday test command
    if message.content.lower().strip() == "!monday":
        await send_monday_video()
        #await message.channel.send("✅ Monday message sent (or attempted). Check logs.")
        return
    
    if globals.AUTO_MOOD and 'response' in locals():
        # Block auto mood updates if forced angry period is active
        now = datetime.datetime.utcnow()
        if globals.FORCED_ANGRY_UNTIL and now < globals.FORCED_ANGRY_UNTIL:
            print("🚫 Skipping auto mood detection — forced angry period active.")
        else:
            detected = detect_mood_shift(response)
            if detected and detected != globals.CURRENT_MOOD_NAME:

                # Block direct transitions to asleep unless from sleepy
                if detected == "asleep" and globals.CURRENT_MOOD_NAME != "sleepy":
                    print("❌ Ignoring asleep mood; Miku wasn't sleepy before.")
                else:
                    globals.PREVIOUS_MOOD_NAME = globals.CURRENT_MOOD_NAME
                    globals.CURRENT_MOOD_NAME = detected
                    globals.CURRENT_MOOD = load_mood_description(detected)
                    await nickname_mood_emoji()
                    print(f"🔄 Auto-updated mood to: {detected}")

                if detected == "asleep":
                    globals.IS_SLEEPING = True
                    await set_sleep_state(True)
                    await asyncio.sleep(3600) # 1 hour
                    globals.IS_SLEEPING = False
                    await set_sleep_state(False)
                    globals.CURRENT_MOOD_NAME = "neutral"
                    globals.CURRENT_MOOD = load_mood_description("neutral")

def start_api():
    uvicorn.run(app, host="0.0.0.0", port=3939, log_level="info")

threading.Thread(target=start_api, daemon=True).start()
globals.client.run(globals.DISCORD_BOT_TOKEN)
