import { query, mutation, internalMutation } from "./_generated/server";
import { v } from "convex/values";
import { internal } from "./_generated/api";

const TYPING_TTL_MS = 6000;

export const startTyping = mutation({
  args: {
    channelId: v.id("channels"),
    userId: v.id("userProfiles"),
    username: v.string(),
  },
  returns: v.null(),
  handler: async (ctx, args) => {
    const expiresAt = Date.now() + TYPING_TTL_MS;

    const existing = await ctx.db
      .query("typingIndicators")
      .withIndex("by_channel", (q) => q.eq("channelId", args.channelId))
      .collect();

    const userTyping = existing.find((t) => t.userId === args.userId);

    if (userTyping) {
      await ctx.db.patch(userTyping._id, { expiresAt });
    } else {
      await ctx.db.insert("typingIndicators", {
        channelId: args.channelId,
        userId: args.userId,
        username: args.username,
        expiresAt,
      });
    }

    await ctx.scheduler.runAfter(TYPING_TTL_MS, internal.typing.cleanExpired, {});
    return null;
  },
});

export const stopTyping = mutation({
  args: {
    channelId: v.id("channels"),
    userId: v.id("userProfiles"),
  },
  returns: v.null(),
  handler: async (ctx, args) => {
    const indicators = await ctx.db
      .query("typingIndicators")
      .withIndex("by_channel", (q) => q.eq("channelId", args.channelId))
      .collect();

    const mine = indicators.find((t) => t.userId === args.userId);
    if (mine) {
      await ctx.db.delete(mine._id);
    }

    return null;
  },
});

export const getTyping = query({
  args: { channelId: v.id("channels") },
  returns: v.array(
    v.object({
      userId: v.id("userProfiles"),
      username: v.string(),
      displayName: v.union(v.string(), v.null()),
    })
  ),
  handler: async (ctx, args) => {
    const now = Date.now();
    const indicators = await ctx.db
      .query("typingIndicators")
      .withIndex("by_channel", (q) => q.eq("channelId", args.channelId))
      .collect();

    const active = indicators.filter((t) => t.expiresAt > now);
    const results = [];
    for (const t of active) {
      const user = await ctx.db.get(t.userId);
      results.push({
        userId: t.userId,
        username: t.username,
        displayName: user?.displayName || null,
      });
    }
    return results;
  },
});

export const cleanExpired = internalMutation({
  args: {},
  returns: v.null(),
  handler: async (ctx) => {
    const now = Date.now();
    const expired = await ctx.db.query("typingIndicators").collect();
    for (const t of expired) {
      if (t.expiresAt <= now) {
        await ctx.db.delete(t._id);
      }
    }
    return null;
  },
});
