import { Inject, Injectable } from '@nestjs/common';
import { OnEvent } from '@nestjs/event-emitter';
import { type BankTransferConfirmedEvent } from '@modules/payments';
import { LoggerService } from '@modules/shared';
import {
  SUBSCRIPTION_REPOSITORY,
  type ISubscriptionRepository,
} from '../../domain/repositories/subscription.repository';

/**
 * Handles subscription activation once a bank-transfer payment is confirmed.
 *
 * A bank-transfer payment whose `type === 'SUBSCRIPTION'` represents a
 * pending subscription activation: the user transferred funds offline and
 * an admin reconciled the payment.
 *
 * We extend the user's current subscription period (or mark it active) so
 * the user regains access immediately after confirmation. Plan selection
 * happens upstream during payment creation; this listener is the
 * side-effect hook that flips the subscription status.
 *
 * Uses ISubscriptionRepository to keep the domain entity authoritative —
 * no raw Prisma access in this handler.
 *
 * NOTE: Intentionally defensive — if no subscription exists yet the event
 * is logged and skipped; downstream processes (CS or renewal cron) pick it up.
 */
@Injectable()
export class BankTransferSubscriptionActivationHandler {
  constructor(
    @Inject(SUBSCRIPTION_REPOSITORY)
    private readonly subscriptionRepo: ISubscriptionRepository,
    private readonly logger: LoggerService,
  ) {}

  @OnEvent('payment.bank_transfer_confirmed', { async: true })
  async handle(event: BankTransferConfirmedEvent): Promise<void> {
    if (event.type !== 'SUBSCRIPTION') {
      return;
    }

    try {
      const subscription = await this.subscriptionRepo.findByUserId(event.userId);

      if (!subscription) {
        this.logger.warn(
          `Bank transfer confirmed for userId=${event.userId} but no subscription found to activate — manual CS review required (paymentId=${event.aggregateId})`,
          'BankTransferSubscriptionActivationHandler',
        );
        return;
      }

      const now = new Date();
      const baseStart =
        subscription.currentPeriodEnd > now ? subscription.currentPeriodStart : now;
      const baseEnd =
        subscription.currentPeriodEnd > now ? subscription.currentPeriodEnd : now;

      // Default to 30-day extension; renewal command handles more granular math
      const nextPeriodEnd = new Date(
        baseEnd.getTime() + 30 * 24 * 60 * 60 * 1000,
      );

      subscription.renewPeriod(baseStart, nextPeriodEnd);
      await this.subscriptionRepo.update(subscription);

      this.logger.log(
        `Subscription activated via bank transfer: subscriptionId=${subscription.id}, userId=${event.userId}, paymentId=${event.aggregateId}, periodEnd=${nextPeriodEnd.toISOString()}`,
        'BankTransferSubscriptionActivationHandler',
      );
    } catch (error) {
      // Never break the confirm flow — log and let ops replay
      this.logger.error(
        `Failed to activate subscription on bank transfer confirmation: paymentId=${event.aggregateId}, userId=${event.userId}`,
        error instanceof Error ? error.stack : String(error),
        'BankTransferSubscriptionActivationHandler',
      );
    }
  }
}
