import { Inject, InternalServerErrorException } from '@nestjs/common';
import { CommandHandler, EventBus, type ICommandHandler } from '@nestjs/cqrs';
import { DomainException, NotFoundException, ValidationException, LoggerService } from '@modules/shared';
import {
  SUBSCRIPTION_REPOSITORY,
  type ISubscriptionRepository,
} from '../../../domain/repositories/subscription.repository';
import { CancelSubscriptionCommand } from './cancel-subscription.command';

export interface CancelSubscriptionResult {
  subscriptionId: string;
  status: string;
  cancelledAt: Date;
}

@CommandHandler(CancelSubscriptionCommand)
export class CancelSubscriptionHandler implements ICommandHandler<CancelSubscriptionCommand> {
  constructor(
    @Inject(SUBSCRIPTION_REPOSITORY)
    private readonly subscriptionRepo: ISubscriptionRepository,
    private readonly eventBus: EventBus,
    private readonly logger: LoggerService,
  ) {}

  async execute(command: CancelSubscriptionCommand): Promise<CancelSubscriptionResult> {
    try {
      const subscription = await this.subscriptionRepo.findByUserId(command.userId);
      if (!subscription) {
        throw new NotFoundException('Subscription', command.userId);
      }

      if (subscription.status === 'CANCELLED') {
        throw new ValidationException('Subscription đã bị hủy trước đó');
      }

      const cancelResult = subscription.cancel();
      if (cancelResult.isErr) {
        throw cancelResult.unwrapErr();
      }
      await this.subscriptionRepo.update(subscription);

      // Publish domain events
      const events = subscription.clearDomainEvents();
      for (const event of events) {
        this.eventBus.publish(event);
      }

      this.logger.log(
        `Subscription cancelled: id=${subscription.id}, user=${command.userId}, reason=${command.reason ?? 'N/A'}`,
        'CancelSubscriptionHandler',
      );

      return {
        subscriptionId: subscription.id,
        status: 'CANCELLED',
        cancelledAt: subscription.cancelledAt!,
      };
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to hủy subscription: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined,
        this.constructor.name,
      );
      throw new InternalServerErrorException('Không thể hủy gói đăng ký. Vui lòng thử lại sau.');
    }
  }
}
