import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { BaseRepository } from "@edr/api-common";
import { NotificationOutbox } from "./entities/notification-outbox.entity";

@Injectable()
export class OutboxRepository extends BaseRepository<NotificationOutbox> {
  constructor(
    @InjectRepository(NotificationOutbox)
    repository: Repository<NotificationOutbox>,
  ) {
    super(repository);
  }

  /**
   * PENDING rows whose retry time has come, oldest first. The relay runs as a single
   * non-overlapping loop per instance; with multiple service instances this should move to a
   * SELECT … FOR UPDATE SKIP LOCKED claim.
   */
  async findDue(limit: number): Promise<NotificationOutbox[]> {
    return this.repository
      .createQueryBuilder("outbox")
      .where(`outbox.status = 'PENDING'`)
      .andWhere(
        "(outbox.next_retry_at IS NULL OR outbox.next_retry_at <= now())",
      )
      .orderBy("outbox.created_at", "ASC")
      .take(limit)
      .getMany();
  }

  async markSent(id: string): Promise<void> {
    await this.update(id, {
      status: "SENT",
      sentAt: new Date(),
      lastError: null,
    });
  }

  async markAttemptFailed(
    row: NotificationOutbox,
    error: string,
    nextRetryAt: Date | null,
    exhausted: boolean,
  ): Promise<void> {
    await this.update(row.id, {
      attempts: row.attempts + 1,
      lastError: error,
      nextRetryAt,
      status: exhausted ? "FAILED" : "PENDING",
    });
  }

  async countBacklog(): Promise<number> {
    return this.repository.count({ where: { status: "PENDING" } });
  }
}
