import { eq, sql, and, lte, isNull, or } from "drizzle-orm";
import { db } from "../../config/database.js";
import {
  outbox,
  type OutboxMessage,
  type NewOutboxMessage,
} from "./outbox.schema.js";

type DbClient = typeof db;

export class OutboxRepository {
  async create(message: NewOutboxMessage, tx: DbClient = db): Promise<void> {
    await tx.insert(outbox).values(message);
  }

  /**
   * 查找待发布消息：
   * - status = 'pending'
   * - next_retry_at IS NULL 或 next_retry_at <= NOW()
   * 按 created_at 升序，取 limit 条
   */
  async findPending(limit: number = 100): Promise<OutboxMessage[]> {
    return db
      .select()
      .from(outbox)
      .where(
        and(
          eq(outbox.status, "pending"),
          or(lte(outbox.nextRetryAt, new Date()), isNull(outbox.nextRetryAt)),
        ),
      )
      .limit(limit);
  }

  async markProcessed(id: string): Promise<void> {
    await db
      .update(outbox)
      .set({ status: "processed", processedAt: new Date() })
      .where(eq(outbox.id, id));
  }

  async incrementRetry(id: string, backoffMs: number): Promise<void> {
    const nextRetryAt = new Date(Date.now() + backoffMs);
    await db
      .update(outbox)
      .set({
        retryCount: sql`${outbox.retryCount} + 1`,
        nextRetryAt,
      })
      .where(eq(outbox.id, id));
  }

  async markFailed(id: string): Promise<void> {
    await db.update(outbox).set({ status: "failed" }).where(eq(outbox.id, id));
  }
}

export const outboxRepository = new OutboxRepository();
