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

export const openDM = mutation({
  args: {
    userId: v.id("userProfiles"),
    targetUserId: v.id("userProfiles"),
  },
  returns: v.object({
    channelId: v.id("channels"),
    created: v.boolean(),
  }),
  handler: async (ctx, args) => {
    if (args.userId === args.targetUserId) {
      throw new Error("Cannot DM yourself");
    }

    const sorted = [args.userId, args.targetUserId].sort();
    const dmName = `dm-${sorted[0]}-${sorted[1]}`;

    const existing = await ctx.db
      .query("channels")
      .withIndex("by_name", (q) => q.eq("name", dmName))
      .unique();

    if (existing) {
      return { channelId: existing._id, created: false };
    }

    const channelId = await ctx.db.insert("channels", {
      name: dmName,
      type: "dm",
    });

    await Promise.all([
      ctx.db.insert("dmParticipants", { channelId, userId: args.userId }),
      ctx.db.insert("dmParticipants", { channelId, userId: args.targetUserId }),
    ]);

    return { channelId, created: true };
  },
});

export const listDMs = query({
  args: { userId: v.id("userProfiles") },
  returns: v.array(
    v.object({
      channel_id: v.id("channels"),
      channel_name: v.string(),
      other_user_id: v.string(),
      other_username: v.string(),
      other_displayName: v.union(v.string(), v.null()),
      other_user_status: v.optional(v.string()),
      other_user_avatar_url: v.optional(v.union(v.string(), v.null())),
    })
  ),
  handler: async (ctx, args) => {
    const myParticipations = await ctx.db
      .query("dmParticipants")
      .withIndex("by_user", (q) => q.eq("userId", args.userId))
      .collect();

    const results = await Promise.all(
      myParticipations.map(async (part) => {
        const channel = await ctx.db.get(part.channelId);
        if (!channel || channel.type !== "dm") return null;

        const otherParts = await ctx.db
          .query("dmParticipants")
          .withIndex("by_channel", (q) => q.eq("channelId", part.channelId))
          .collect();

        const otherPart = otherParts.find((p) => p.userId !== args.userId);
        if (!otherPart) return null;

        const otherUser = await ctx.db.get(otherPart.userId);
        if (!otherUser) return null;

        const avatarUrl = otherUser.avatarStorageId
          ? await getPublicStorageUrl(ctx, otherUser.avatarStorageId)
          : null;

        return {
          channel_id: part.channelId,
          channel_name: channel.name,
          other_user_id: otherUser._id as string,
          other_username: otherUser.username,
          other_displayName: otherUser.displayName || null,
          other_user_status: otherUser.status || "offline",
          other_user_avatar_url: avatarUrl,
        };
      })
    );

    return results.filter((r): r is NonNullable<typeof r> => r !== null);
  },
});
