# api.py

from fastapi import (
        FastAPI,
        Query,
        BackgroundTasks,
        Request, UploadFile,
        File,
        Form
)
from typing import List
from pydantic import BaseModel
import globals
from commands.actions import (
    force_sleep,
    wake_up,
    set_mood,
    reset_mood,
    check_mood,
    calm_miku,
    reset_conversation,
    send_bedtime_now
)
from utils.moods import nickname_mood_emoji
from utils.autonomous import (
        miku_autonomous_tick,
        miku_say_something_general,
        miku_engage_random_user,
        share_miku_tweet,
        handle_custom_prompt
)
import asyncio
import nest_asyncio
import subprocess
import io
import discord
import aiofiles
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse, PlainTextResponse
nest_asyncio.apply()

app = FastAPI()

# Serve static folder
app.mount("/static", StaticFiles(directory="static"), name="static")

# ========== Models ==========
class MoodSetRequest(BaseModel):
    mood: str

class ConversationResetRequest(BaseModel):
    user_id: str

class CustomPromptRequest(BaseModel):
    prompt: str

# ========== Routes ==========
@app.get("/")
def read_index():
    return FileResponse("static/index.html")

@app.get("/logs")
def get_logs():
    try:
        # Read last 100 lines of the log file
        with open("/app/bot.log", "r", encoding="utf-8") as f:
            lines = f.readlines()
        last_100 = lines[-100:]
        return "".join(lines[-100] if len(lines) >= 100 else lines)
    except Exception as e:
        return f"Error reading log file: {e}"

@app.get("/prompt")
def get_last_prompt():
    return {"prompt": globals.LAST_FULL_PROMPT or "No prompt has been issued yet."}

@app.get("/mood")
def get_current_mood():
    return {"mood": check_mood()}


@app.post("/mood")
async def set_mood_endpoint(data: MoodSetRequest):
    success = set_mood(data.mood)
    if success:
        globals.client.loop.create_task(nickname_mood_emoji())
        return {"status": "ok", "new_mood": data.mood}
    return {"status": "error", "message": "Mood not recognized"}


@app.post("/mood/reset")
async def reset_mood_endpoint(background_tasks: BackgroundTasks):
    reset_mood()
    globals.client.loop.create_task(nickname_mood_emoji())
    return {"status": "ok", "new_mood": "neutral"}


@app.post("/mood/calm")
def calm_miku_endpoint():
    calm_miku()
    return {"status": "ok", "message": "Miku has calmed down."}


@app.post("/conversation/reset")
def reset_convo(data: ConversationResetRequest):
    reset_conversation(data.user_id)
    return {"status": "ok", "message": f"Memory reset for {data.user_id}"}


@app.post("/sleep")
async def force_sleep_endpoint():
    await force_sleep()
    globals.client.loop.create_task(nickname_mood_emoji())
    return {"status": "ok", "message": "Miku is now sleeping"}


@app.post("/wake")
async def wake_up_endpoint():
    await wake_up()
    globals.client.loop.create_task(nickname_mood_emoji())
    return {"status": "ok", "message": "Miku is now awake"}


@app.post("/bedtime")
async def bedtime_endpoint(background_tasks: BackgroundTasks):
    globals.client.loop.create_task(send_bedtime_now())
    return {"status": "ok", "message": "Bedtime message sent"}

@app.post("/autonomous/general")
async def trigger_autonomous_general():
    globals.client.loop.create_task(miku_autonomous_tick(force=True, force_action="general"))
    return {"status": "ok", "message": "Miku say something general triggered manually"}

@app.post("/autonomous/engage")
async def trigger_autonomous_engage_user():
    globals.client.loop.create_task(miku_autonomous_tick(force=True, force_action="engage_user"))
    return {"status": "ok", "message": "Miku engage random user triggered manually"}

@app.post("/autonomous/tweet")
async def trigger_autonomous_tweet():
    globals.client.loop.create_task(miku_autonomous_tick(force=True, force_action="share_tweet"))
    return {"status": "ok", "message": "Miku share tweet triggered manually"}

@app.post("/autonomous/custom")
async def custom_autonomous_message(req: CustomPromptRequest):
    try:
        asyncio.run_coroutine_threadsafe(
            handle_custom_prompt(req.prompt), globals.client.loop
        )
        return {"success": True, "message": "Miku is working on it!"}
    except Exception as e:
        print(f"❌ Error running custom prompt in bot loop: {repr(e)}")
        return {"success": False, "error": str(e)}

@app.post("/manual/send")
async def manual_send(
    message: str = Form(...),
    channel_id: str = Form(...),
    files: List[UploadFile] = File(default=[])
):
    try:
        # Get the Discord channel Miku should post in
        channel = globals.client.get_channel(int(channel_id))
        if not channel:
            return {"success": False, "error": "Target channel not found"}

       # Prepare file data (read in the async FastAPI thread)
        prepared_files = []
        for f in files:
            contents = await f.read()
            prepared_files.append((f.filename, contents))

        # Define a coroutine that will run inside the bot loop
        async def send_message():
            channel = globals.client.get_channel(int(channel_id))
            if not channel:
                raise ValueError(f"Channel ID {channel_id} not found or bot cannot access it.")

            discord_files = [
                discord.File(io.BytesIO(content), filename=filename)
                for filename, content in prepared_files
            ]

            await channel.send(content=message or None, files=discord_files or None)

        # Schedule coroutine in bot's event loop
        future = asyncio.run_coroutine_threadsafe(send_message(), globals.client.loop)
        future.result(timeout=10)  # Wait max 10 seconds for it to finish

        return {"success": True}
 

    except Exception as e:
        print(f"❌ Error in /manual/send: {repr(e)}")
        return {"success": False, "error": str(e)}

@app.get("/status")
def status():
    return {
        "mood": globals.CURRENT_MOOD_NAME,
        "is_sleeping": globals.IS_SLEEPING,
        "previous_mood": globals.PREVIOUS_MOOD_NAME
    }

@app.get("/conversation/{user_id}")
def get_conversation(user_id: str):
    return globals.conversation_history.get(user_id, [])
