import { Injectable } from '@nestjs/common';
import { EventBus } from '@nestjs/cqrs';
import { Cron, CronExpression } from '@nestjs/schedule';
import { Prisma } from '@prisma/client';
import { PrismaService, LoggerService } from '@modules/shared';
import { ListingFeaturedExpiredEvent } from '../../domain/events/listing-featured-expired.event';

/**
 * Cron service that automatically clears the `featuredUntil` column on listings
 * whose featured promotion period has ended (`featuredUntil < now()`).
 *
 * Design notes:
 * - Runs every 5 minutes (`@Cron(CronExpression.EVERY_5_MINUTES)`).
 * - Uses a single atomic SQL `UPDATE ... RETURNING id` so the operation is safe to
 *   run on multiple instances concurrently — only one transaction will satisfy
 *   the `featuredUntil < NOW()` predicate per row, and subsequent runs see no
 *   rows to update (idempotent).
 * - Publishes `ListingFeaturedExpiredEvent` per affected listing so search index
 *   and cache layers can invalidate.
 */
@Injectable()
export class FeaturedListingExpiryCronService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly eventBus: EventBus,
    private readonly logger: LoggerService,
  ) {}

  @Cron(CronExpression.EVERY_5_MINUTES, { name: 'featured-listing-expiry' })
  async expireFeaturedListings(): Promise<void> {
    const startedAt = new Date();
    try {
      const expired = await this.prisma.$queryRaw<Array<{ id: string }>>(Prisma.sql`
        UPDATE "Listing"
        SET "featuredUntil" = NULL,
            "featuredPackage" = NULL,
            "updatedAt" = NOW()
        WHERE "featuredUntil" IS NOT NULL
          AND "featuredUntil" < NOW()
        RETURNING id
      `);

      if (expired.length === 0) {
        this.logger.debug(
          'No featured listings to expire',
          'FeaturedListingExpiryCronService',
        );
        return;
      }

      for (const row of expired) {
        this.eventBus.publish(new ListingFeaturedExpiredEvent(row.id, startedAt));
      }

      this.logger.log(
        `Expired ${expired.length} featured listing(s) at ${startedAt.toISOString()}`,
        'FeaturedListingExpiryCronService',
      );
    } catch (err) {
      this.logger.error(
        `Failed to expire featured listings: ${(err as Error).message}`,
        (err as Error).stack,
        'FeaturedListingExpiryCronService',
      );
    }
  }
}
