import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { In, LessThan, Not, Repository } from "typeorm";
import { BaseRepository } from "@edr/api-common";
import {
  PaymentReferenceType,
  PaymentService,
  ProviderPaymentStatus,
} from "@edr/types";
import { PaymentIntent } from "./entities/payment-intent.entity";

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

  /** The single non-FAILED/CANCELLED intent for a domain order (matches the partial unique index). */
  async findActiveByReference(
    service: PaymentService,
    referenceType: PaymentReferenceType,
    referenceId: string,
  ): Promise<PaymentIntent | null> {
    return this.repository.findOne({
      where: {
        service,
        referenceType,
        referenceId,
        status: Not(
          In([ProviderPaymentStatus.FAILED, ProviderPaymentStatus.CANCELLED]),
        ),
      },
      order: { createdAt: "DESC" },
    });
  }

  async findByMerchantOrderId(
    merchantOrderId: string,
  ): Promise<PaymentIntent | null> {
    return this.repository.findOne({ where: { merchantOrderId } });
  }

  async findByIdempotencyKey(
    service: PaymentService,
    idempotencyKey: string,
  ): Promise<PaymentIntent | null> {
    return this.repository.findOne({
      where: { service, idempotencyKey },
      order: { createdAt: "DESC" },
    });
  }

  /** Non-terminal intents untouched since `updatedBefore` — input for the reconciliation sweep. */
  async findStale(
    updatedBefore: Date,
    limit: number,
  ): Promise<PaymentIntent[]> {
    return this.repository.find({
      where: {
        status: In([
          ProviderPaymentStatus.REQUIRES_ACTION,
          ProviderPaymentStatus.PROCESSING,
        ]),
        updatedAt: LessThan(updatedBefore),
      },
      order: { updatedAt: "ASC" },
      take: limit,
    });
  }
}
