import { Injectable, Logger } from '@nestjs/common'
import { ConfigService } from '@nestjs/config'
import { Cron } from '@nestjs/schedule'
import { BookingsService } from './bookings.service.js'

// Calendar-write retry queue (§8.2.4). When the synchronous Stalwart calendar
// write fails during confirmation, the booking is left 'pending' with its
// SlotLock retained (rather than deleted). This cron periodically re-drives the
// write for those pending bookings: on success the booking is promoted to
// 'confirmed' and the confirmation email is sent; once attempts hit the cap the
// booking moves to the terminal 'calendar_failed' state and its lock is
// released. The per-booking attempt counter (and idempotent calendarEventUid)
// lives on the Booking, so this worker is safe to run repeatedly. Max attempts
// is configurable via SCHEDULING_CALENDAR_RETRY_MAX (default 5).
@Injectable()
export class CalendarRetryWorker {
  private readonly logger = new Logger(CalendarRetryWorker.name)
  private readonly maxAttempts: number

  constructor(
    private readonly bookings: BookingsService,
    config: ConfigService,
  ) {
    const raw = Number(config.get<string>('SCHEDULING_CALENDAR_RETRY_MAX'))
    this.maxAttempts = Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 5
  }

  // Every 2 minutes (@nestjs/schedule has no EVERY_2_MINUTES preset).
  @Cron('*/2 * * * *', { name: 'calendar-write-retry' })
  async run(): Promise<void> {
    const pending = await this.bookings.findPendingForRetry(this.maxAttempts)
    if (pending.length === 0) return

    this.logger.log(`Retrying calendar writes for ${pending.length} pending booking(s)`)
    for (const booking of pending) {
      await this.bookings
        .retryPendingCalendarWrite(booking, this.maxAttempts)
        .catch((e) => this.logger.warn(`Calendar retry failed for booking ${booking._id}: ${e.message}`))
    }
  }
}
