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 user's spaces (where they are a member)
export const list = query({
  args: {},
  handler: async (ctx) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) return [];

    const memberships = await ctx.db
      .query("spaceMembers")
      .withIndex("by_user", (q) => q.eq("userId", userId))
      .filter((q) => q.eq(q.field("isKicked"), false))
      .collect();

    const spaces = await Promise.all(
      memberships.map((m) => ctx.db.get(m.spaceId))
    );

    return spaces.filter((s) => s !== null);
  },
});

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

    const space = await ctx.db.get(args.id);
    if (!space) return null;

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

    return space;
  },
});

// Get space members with presence
export const getMembers = 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 members = await ctx.db
      .query("spaceMembers")
      .withIndex("by_space", (q) => q.eq("spaceId", args.spaceId))
      .filter((q) => q.eq(q.field("isKicked"), false))
      .collect();

    const membersWithDetails = await Promise.all(
      members.map(async (m) => {
        const user = await ctx.db.get(m.userId);
        const profile = await ctx.db
          .query("userProfiles")
          .withIndex("by_user", (q) => q.eq("userId", m.userId))
          .first();
        const presence = await ctx.db
          .query("userPresence")
          .withIndex("by_user", (q) => q.eq("userId", m.userId))
          .first();
        return { ...m, user, profile, presence };
      })
    );

    return membersWithDetails;
  },
});

// Create a space
export const create = mutation({
  args: {
    name: v.string(),
    showcaseConfig: v.optional(
      v.object({
        theme: v.optional(
          v.object({
            primaryColor: v.string(),
            backgroundColor: v.string(),
            backgroundImage: v.optional(v.string()),
          })
        ),
      })
    ),
  },
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new Error("Not authenticated");

    const spaceId = await ctx.db.insert("spaces", {
      name: args.name,
      ownerId: userId,
      isHomeSpace: false,
      showcaseConfig: args.showcaseConfig || {
        theme: {
          primaryColor: "#3b82f6",
          backgroundColor: "#1f2937",
        },
      },
    });

    // Create space member record for owner
    await ctx.db.insert("spaceMembers", {
      spaceId,
      userId,
      role: "owner",
      joinedAt: Date.now(),
      isKicked: false,
    });

    // Create default general room
    await ctx.db.insert("rooms", {
      spaceId,
      name: "general",
      type: "chat",
    });

    return spaceId;
  },
});

// Update space settings
export const update = mutation({
  args: {
    spaceId: v.id("spaces"),
    name: v.optional(v.string()),
    showcaseConfig: v.optional(
      v.object({
        theme: v.optional(
          v.object({
            primaryColor: v.string(),
            backgroundColor: v.string(),
            backgroundImage: v.optional(v.string()),
          })
        ),
      })
    ),
  },
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new Error("Not authenticated");

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

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

// Delete space
export const deleteSpace = mutation({
  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 owner
    if (!(await isOwner(ctx, args.spaceId, userId))) {
      throw new Error("Not authorized - owner only");
    }

    // Delete all space members
    const members = await ctx.db
      .query("spaceMembers")
      .withIndex("by_space", (q) => q.eq("spaceId", args.spaceId))
      .collect();
    await Promise.all(members.map((m) => ctx.db.delete(m._id)));

    // Delete all invites
    const invites = await ctx.db
      .query("spaceInvites")
      .withIndex("by_space", (q) => q.eq("spaceId", args.spaceId))
      .collect();
    await Promise.all(invites.map((i) => ctx.db.delete(i._id)));

    // Delete all rooms and their messages
    const rooms = await ctx.db
      .query("rooms")
      .withIndex("by_space", (q) => q.eq("spaceId", args.spaceId))
      .collect();
    for (const room of rooms) {
      const messages = await ctx.db
        .query("messages")
        .withIndex("by_room", (q) => q.eq("roomId", room._id))
        .collect();
      await Promise.all(messages.map((m) => ctx.db.delete(m._id)));
      await ctx.db.delete(room._id);
    }

    // Delete presence records
    const presences = await ctx.db
      .query("userPresence")
      .withIndex("by_space", (q) => q.eq("spaceId", args.spaceId))
      .collect();
    await Promise.all(presences.map((p) => ctx.db.delete(p._id)));

    // Delete space
    await ctx.db.delete(args.spaceId);
  },
});

// Kick member from space
export const kickMember = mutation({
  args: {
    spaceId: v.id("spaces"),
    userId: v.id("users"),
  },
  handler: async (ctx, args) => {
    const currentUserId = await getAuthUserId(ctx);
    if (!currentUserId) throw new Error("Not authenticated");

    // Check if current user is owner
    if (!(await isOwner(ctx, args.spaceId, currentUserId))) {
      throw new Error("Not authorized - owner only");
    }

    // Can't kick yourself
    if (currentUserId === args.userId) {
      throw new Error("Cannot kick yourself");
    }

    // Find member record
    const member = await ctx.db
      .query("spaceMembers")
      .withIndex("by_space_and_user", (q) =>
        q.eq("spaceId", args.spaceId).eq("userId", args.userId)
      )
      .first();

    if (!member) throw new Error("Member not found");

    // Mark as kicked
    await ctx.db.patch(member._id, { isKicked: true });
  },
});
