import { query, mutation } from "./_generated/server";
import { getAuthUserId } from "@convex-dev/auth/server";
import { v } from "convex/values";
import { paginationOptsValidator } from "convex/server";
import { internal } from "./_generated/api";
import { ASSISTANT_MENTION } from "./assistant";

// Helper to check if user has access to a room
async function hasRoomAccess(ctx: any, roomId: string, userId: string) {
  const room = await ctx.db.get(roomId);
  if (!room) return false;

  // Check if user is a member of the space
  const member = await ctx.db
    .query("spaceMembers")
    .withIndex("by_space_and_user", (q: any) =>
      q.eq("spaceId", room.spaceId).eq("userId", userId)
    )
    .first();
  if (!member || member.isKicked) return false;

  // Check private room access
  if (room.isPrivate && room.allowlist && !room.allowlist.includes(userId)) {
    return false;
  }

  return true;
}

// Query messages with pagination
export const list = query({
  args: {
    roomId: v.id("rooms"),
    paginationOpts: paginationOptsValidator,
  },
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new Error("Not authenticated");

    // Check room access
    if (!(await hasRoomAccess(ctx, args.roomId, userId))) {
      throw new Error("Not authorized");
    }

    return await ctx.db
      .query("messages")
      .withIndex("by_room_and_timestamp", (q) =>
        q.eq("roomId", args.roomId)
      )
      .order("desc")
      .paginate(args.paginationOpts);
  },
});

// Send message
export const send = mutation({
  args: {
    roomId: v.id("rooms"),
    content: v.string(),
    mentions: v.optional(v.array(v.union(v.id("users"), v.literal("suno"), v.literal("orphy")))),
    atomIds: v.optional(v.array(v.id("atoms"))),
  },
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new Error("Not authenticated");

    // Check room access
    if (!(await hasRoomAccess(ctx, args.roomId, userId))) {
      throw new Error("Not authorized");
    }

    const messageId = await ctx.db.insert("messages", {
      roomId: args.roomId,
      userId,
      content: args.content,
      timestamp: Date.now(),
      mentions: args.mentions,
      reactions: [],
      atomReferences: args.atomIds,
    });

    // Check if @suno (or legacy @orphy) was mentioned and trigger assistant
    if (args.mentions?.includes(ASSISTANT_MENTION as any) ||
        args.mentions?.includes("orphy" as any)) {
      await ctx.scheduler.runAfter(0, internal.assistant.handleMessage, {
        messageId,
      });
    }

    return messageId;
  },
});

// Add reaction to message
export const addReaction = mutation({
  args: {
    messageId: v.id("messages"),
    emoji: v.string(),
  },
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new Error("Not authenticated");

    const message = await ctx.db.get(args.messageId);
    if (!message) throw new Error("Message not found");

    // Check room access
    if (!(await hasRoomAccess(ctx, message.roomId, userId))) {
      throw new Error("Not authorized");
    }

    // Check if user already reacted with this emoji
    const reactions = message.reactions || [];
    const existingReaction = reactions.find(
      (r) => r.userId === userId && r.emoji === args.emoji
    );

    if (existingReaction) {
      return; // Already reacted
    }

    // Add reaction
    await ctx.db.patch(args.messageId, {
      reactions: [...reactions, { emoji: args.emoji, userId }],
    });
  },
});

// Remove reaction from message
export const removeReaction = mutation({
  args: {
    messageId: v.id("messages"),
    emoji: v.string(),
  },
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new Error("Not authenticated");

    const message = await ctx.db.get(args.messageId);
    if (!message) throw new Error("Message not found");

    // Check room access
    if (!(await hasRoomAccess(ctx, message.roomId, userId))) {
      throw new Error("Not authorized");
    }

    // Remove reaction
    const reactions = message.reactions || [];
    await ctx.db.patch(args.messageId, {
      reactions: reactions.filter(
        (r) => !(r.userId === userId && r.emoji === args.emoji)
      ),
    });
  },
});

// Delete own message
export const deleteMessage = mutation({
  args: { messageId: v.id("messages") },
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new Error("Not authenticated");

    const message = await ctx.db.get(args.messageId);
    if (!message) throw new Error("Message not found");

    // Check if user owns the message
    if (message.userId !== userId) {
      throw new Error("Not authorized - can only delete your own messages");
    }

    await ctx.db.delete(args.messageId);
  },
});
