import { query, mutation } from "./_generated/server";
import { v } from "convex/values";
import { getRolesForUser } from "./roles";
import { getPublicStorageUrl } from "./storageUrl";

export const list = query({
  args: {},
  returns: v.any(),
  handler: async (ctx) => {
    const emojis = await ctx.db.query("customEmojis").collect();
    const results = await Promise.all(
      emojis.map(async (emoji) => {
        const src = await getPublicStorageUrl(ctx, emoji.storageId);
        const user = await ctx.db.get(emoji.uploadedBy);
        let avatarUrl: string | null = null;
        if (user?.avatarStorageId) {
          avatarUrl = await getPublicStorageUrl(ctx, user.avatarStorageId);
        }
        return {
          _id: emoji._id,
          name: emoji.name,
          src,
          createdAt: emoji.createdAt,
          animated: emoji.animated ?? false,
          uploadedById: emoji.uploadedBy,
          uploadedByUsername: user?.username || "Unknown",
          uploadedByDisplayName: user?.displayName || null,
          uploadedByAvatarUrl: avatarUrl,
        };
      })
    );
    return results.filter((e) => e.src !== null);
  },
});

export const upload = mutation({
  args: {
    userId: v.id("userProfiles"),
    name: v.string(),
    storageId: v.id("_storage"),
    animated: v.optional(v.boolean()),
  },
  returns: v.null(),
  handler: async (ctx, args) => {
    // Permission check
    const roles = await getRolesForUser(ctx, args.userId);
    const canManage = roles.some(
      (role) => (role.permissions as Record<string, boolean>)?.["manage_channels"]
    );
    if (!canManage) {
      throw new Error("You don't have permission to manage emojis");
    }

    // Validate name format
    const name = args.name.trim();
    if (!/^[a-zA-Z0-9_]+$/.test(name)) {
      throw new Error("Emoji name can only contain letters, numbers, and underscores");
    }
    if (name.length < 2 || name.length > 32) {
      throw new Error("Emoji name must be between 2 and 32 characters");
    }

    // Check for duplicate name among custom emojis
    const existing = await ctx.db
      .query("customEmojis")
      .withIndex("by_name", (q) => q.eq("name", name))
      .first();
    if (existing) {
      throw new Error(`A custom emoji named "${name}" already exists`);
    }

    await ctx.db.insert("customEmojis", {
      name,
      storageId: args.storageId,
      uploadedBy: args.userId,
      animated: args.animated ?? false,
      createdAt: Date.now(),
    });

    return null;
  },
});

/**
 * Rename a custom emoji in place. Enforces the same name validation
 * as `upload` and rejects collisions with other existing emojis so
 * two rows can't end up sharing a shortcode.
 */
export const rename = mutation({
  args: {
    userId: v.id("userProfiles"),
    emojiId: v.id("customEmojis"),
    name: v.string(),
  },
  returns: v.null(),
  handler: async (ctx, args) => {
    const roles = await getRolesForUser(ctx, args.userId);
    const canManage = roles.some(
      (role) => (role.permissions as Record<string, boolean>)?.["manage_channels"]
    );
    if (!canManage) {
      throw new Error("You don't have permission to manage emojis");
    }

    const emoji = await ctx.db.get(args.emojiId);
    if (!emoji) throw new Error("Emoji not found");

    const name = args.name.trim();
    if (!/^[a-zA-Z0-9_]+$/.test(name)) {
      throw new Error("Emoji name can only contain letters, numbers, and underscores");
    }
    if (name.length < 2 || name.length > 32) {
      throw new Error("Emoji name must be between 2 and 32 characters");
    }

    if (name !== emoji.name) {
      const clash = await ctx.db
        .query("customEmojis")
        .withIndex("by_name", (q) => q.eq("name", name))
        .first();
      if (clash && clash._id !== args.emojiId) {
        throw new Error(`A custom emoji named "${name}" already exists`);
      }
    }

    await ctx.db.patch(args.emojiId, { name });
    return null;
  },
});

export const remove = mutation({
  args: {
    userId: v.id("userProfiles"),
    emojiId: v.id("customEmojis"),
  },
  returns: v.null(),
  handler: async (ctx, args) => {
    // Permission check
    const roles = await getRolesForUser(ctx, args.userId);
    const canManage = roles.some(
      (role) => (role.permissions as Record<string, boolean>)?.["manage_channels"]
    );
    if (!canManage) {
      throw new Error("You don't have permission to manage emojis");
    }

    const emoji = await ctx.db.get(args.emojiId);
    if (!emoji) throw new Error("Emoji not found");

    await ctx.storage.delete(emoji.storageId);
    await ctx.db.delete(args.emojiId);

    return null;
  },
});
