import { mutation } from "../_generated/server";
import { v } from "convex/values";

/**
 * Create a sync queue entry
 * WU-18: Sync domain
 */
export const createSyncTask = mutation({
  args: {
    table: v.string(),
    operation: v.string(),
    data: v.any(),
    conflictColumn: v.string(),
    maxAttempts: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    const now = Date.now();
    const id = await ctx.db.insert("sync_queue", {
      table: args.table,
      operation: args.operation,
      data: args.data,
      conflictColumn: args.conflictColumn,
      attempts: 0,
      maxAttempts: args.maxAttempts ?? 5,
      nextRetryAt: now,
      createdAt: now,
    });
    return id;
  },
});

/**
 * Update sync task status (mark as processed or failed)
 * WU-18: Sync domain
 */
export const updateSyncTask = mutation({
  args: {
    id: v.id("sync_queue"),
    status: v.string(),
    error: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    const task = await ctx.db.get(args.id);
    if (!task) {
      throw new Error(`Sync task ${args.id} not found`);
    }

    if (args.status === "completed") {
      await ctx.db.delete(args.id);
      return { completed: true };
    }

    // Failed - increment attempts
    const newAttempts = task.attempts + 1;

    if (newAttempts >= task.maxAttempts) {
      // Move to DLQ
      await ctx.db.insert("sync_queue_dlq", {
        originalId: args.id as unknown as string,
        table: task.table,
        operation: task.operation,
        data: task.data,
        conflictColumn: task.conflictColumn,
        attempts: newAttempts,
        lastError: args.error,
        originalCreated: task.createdAt,
        movedToDlqAt: Date.now(),
      });
      await ctx.db.delete(args.id);
      return { movedToDlq: true };
    }

    // Retry with exponential backoff
    const delay = Math.min(1000 * Math.pow(2, newAttempts), 300000);
    await ctx.db.patch(args.id, {
      attempts: newAttempts,
      lastError: args.error,
      nextRetryAt: Date.now() + delay,
    });

    return { retrying: true, attempt: newAttempts };
  },
});

/**
 * Process pending sync tasks (batch mark as started)
 * WU-18: Sync domain
 */
export const processSyncQueue = mutation({
  args: {
    limit: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    const limit = args.limit ?? 50;
    const now = Date.now();

    const tasks = await ctx.db
      .query("sync_queue")
      .withIndex("by_nextRetryAt_attempts", (q) => q.lte("nextRetryAt", now))
      .take(limit);

    // Mark tasks as in-progress by pushing nextRetryAt forward
    const processingDelay = 5 * 60 * 1000; // 5 minutes
    for (const task of tasks) {
      await ctx.db.patch(task._id, {
        nextRetryAt: now + processingDelay,
      });
    }

    return {
      count: tasks.length,
      taskIds: tasks.map((t) => t._id),
    };
  },
});
