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

// Helper to generate random invite code
function generateInviteCode(): string {
  const chars = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789";
  let code = "";
  for (let i = 0; i < 8; i++) {
    code += chars.charAt(Math.floor(Math.random() * chars.length));
  }
  return code;
}

// Helper to check if user is owner
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;
}

// Generate invite link/code
export const generate = mutation({
  args: {
    spaceId: v.id("spaces"),
    expiresInDays: v.optional(v.number()),
  },
  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 code = generateInviteCode();
    const expiresAt = args.expiresInDays
      ? Date.now() + args.expiresInDays * 24 * 60 * 60 * 1000
      : undefined;

    const inviteId = await ctx.db.insert("spaceInvites", {
      spaceId: args.spaceId,
      code,
      createdBy: userId,
      createdAt: Date.now(),
      expiresAt,
    });

    return { inviteId, code };
  },
});

// Validate and use invite code to join space
export const useInvite = mutation({
  args: { code: v.string() },
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new Error("Not authenticated");

    // Find invite by code
    const invite = await ctx.db
      .query("spaceInvites")
      .withIndex("by_code", (q) => q.eq("code", args.code))
      .first();

    if (!invite) throw new Error("Invalid invite code");

    // Check if expired
    if (invite.expiresAt && invite.expiresAt < Date.now()) {
      throw new Error("Invite code expired");
    }

    // Check if user is already a member
    const existingMember = await ctx.db
      .query("spaceMembers")
      .withIndex("by_space_and_user", (q) =>
        q.eq("spaceId", invite.spaceId).eq("userId", userId)
      )
      .first();

    if (existingMember) {
      if (existingMember.isKicked) {
        // Unkick if they were previously kicked
        await ctx.db.patch(existingMember._id, {
          isKicked: false,
          joinedAt: Date.now(),
        });
      }
      return { spaceId: invite.spaceId, alreadyMember: true };
    }

    // Add user as member
    await ctx.db.insert("spaceMembers", {
      spaceId: invite.spaceId,
      userId,
      role: "member",
      joinedAt: Date.now(),
      isKicked: false,
    });

    return { spaceId: invite.spaceId, alreadyMember: false };
  },
});

// List active invites for 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 owner
    if (!(await isOwner(ctx, args.spaceId, userId))) {
      throw new Error("Not authorized - owner only");
    }

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

    // Filter out expired invites
    return invites.filter(
      (i) => !i.expiresAt || i.expiresAt > Date.now()
    );
  },
});

// Revoke invite
export const revoke = mutation({
  args: { inviteId: v.id("spaceInvites") },
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new Error("Not authenticated");

    const invite = await ctx.db.get(args.inviteId);
    if (!invite) throw new Error("Invite not found");

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

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