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

// Helper to check if user is a member of a space
async function isMember(ctx: any, spaceId: string, userId: string) {
  const member = await ctx.db
    .query("spaceMembers")
    .withIndex("by_space_and_user", (q: any) =>
      q.eq("spaceId", spaceId).eq("userId", userId)
    )
    .first();
  return member && !member.isKicked;
}

// Helper to check if user is owner of a space
async function isOwner(ctx: any, spaceId: string, userId: string) {
  const member = await ctx.db
    .query("spaceMembers")
    .withIndex("by_space_and_user", (q: any) =>
      q.eq("spaceId", spaceId).eq("userId", userId)
    )
    .first();
  return member && member.role === "owner" && !member.isKicked;
}

// List rooms in a space
export const list = query({
  args: { spaceId: v.id("spaces") },
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new Error("Not authenticated");

    // Check if user is a member
    if (!(await isMember(ctx, args.spaceId, userId))) {
      throw new Error("Not authorized");
    }

    const rooms = await ctx.db
      .query("rooms")
      .withIndex("by_space", (q) => q.eq("spaceId", args.spaceId))
      .collect();

    // Filter out private rooms user doesn't have access to
    return rooms.filter((room) => {
      if (!room.isPrivate) return true;
      if (!room.allowlist) return false;
      return room.allowlist.includes(userId);
    });
  },
});

// Get a specific room
export const get = query({
  args: { roomId: v.id("rooms") },
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new Error("Not authenticated");

    const room = await ctx.db.get(args.roomId);
    if (!room) return null;

    // Check if user is a member of the space
    if (!(await isMember(ctx, room.spaceId, userId))) {
      throw new Error("Not authorized");
    }

    // Check private room access
    if (room.isPrivate && room.allowlist && !room.allowlist.includes(userId)) {
      throw new Error("Not authorized - private room");
    }

    return room;
  },
});

// Create room in space
export const create = mutation({
  args: {
    spaceId: v.id("spaces"),
    name: v.string(),
    type: v.string(),
    isPrivate: v.optional(v.boolean()),
    allowlist: v.optional(v.array(v.id("users"))),
    backgroundConfig: v.optional(
      v.object({
        type: v.union(v.literal("image"), v.literal("gradient"), v.literal("solid")),
        imageUrl: v.optional(v.string()),
        gradientStart: v.optional(v.string()),
        gradientEnd: v.optional(v.string()),
        solidColor: v.optional(v.string()),
      })
    ),
  },
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new Error("Not authenticated");

    // Check if user is a member (not just owner - any member can create rooms)
    if (!(await isMember(ctx, args.spaceId, userId))) {
      throw new Error("Not authorized - must be a space member");
    }

    const roomId = await ctx.db.insert("rooms", {
      spaceId: args.spaceId,
      name: args.name,
      type: args.type,
      isPrivate: args.isPrivate,
      allowlist: args.allowlist,
      backgroundConfig: args.backgroundConfig,
    });

    return roomId;
  },
});

// Update room settings
export const update = mutation({
  args: {
    roomId: v.id("rooms"),
    name: v.optional(v.string()),
    isPrivate: v.optional(v.boolean()),
    allowlist: v.optional(v.array(v.id("users"))),
    backgroundConfig: v.optional(
      v.object({
        type: v.union(v.literal("image"), v.literal("gradient"), v.literal("solid")),
        imageUrl: v.optional(v.string()),
        gradientStart: v.optional(v.string()),
        gradientEnd: v.optional(v.string()),
        solidColor: v.optional(v.string()),
      })
    ),
  },
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new Error("Not authenticated");

    const room = await ctx.db.get(args.roomId);
    if (!room) throw new Error("Room not found");

    // Check if user is owner of the space
    if (!(await isOwner(ctx, room.spaceId, userId))) {
      throw new Error("Not authorized - owner only");
    }

    const { roomId, ...updates } = args;
    await ctx.db.patch(roomId, updates);
    return await ctx.db.get(roomId);
  },
});

// Delete room
export const deleteRoom = mutation({
  args: { roomId: v.id("rooms") },
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new Error("Not authenticated");

    const room = await ctx.db.get(args.roomId);
    if (!room) throw new Error("Room not found");

    // Check if user is owner of the space
    if (!(await isOwner(ctx, room.spaceId, userId))) {
      throw new Error("Not authorized - owner only");
    }

    // Delete all messages in the room
    const messages = await ctx.db
      .query("messages")
      .withIndex("by_room", (q) => q.eq("roomId", args.roomId))
      .collect();
    await Promise.all(messages.map((m) => ctx.db.delete(m._id)));

    // Delete room
    await ctx.db.delete(args.roomId);
  },
});
