import { Inject, InternalServerErrorException } from '@nestjs/common';
import { CommandHandler, EventBus, type ICommandHandler } from '@nestjs/cqrs';
import { createId } from '@paralleldrive/cuid2';
import { DomainException, NotFoundException, ConflictException, PrismaService, LoggerService } from '@modules/shared';
import { SubscriptionEntity } from '../../../domain/entities/subscription.entity';
import {
  SUBSCRIPTION_REPOSITORY,
  type ISubscriptionRepository,
} from '../../../domain/repositories/subscription.repository';
import { CreateSubscriptionCommand } from './create-subscription.command';

export interface CreateSubscriptionResult {
  subscriptionId: string;
  planTier: string;
  status: string;
  currentPeriodStart: Date;
  currentPeriodEnd: Date;
}

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

  async execute(command: CreateSubscriptionCommand): Promise<CreateSubscriptionResult> {
    try {
      // Check if user already has an active subscription
      const existing = await this.subscriptionRepo.findByUserId(command.userId);
      if (existing && (existing.status === 'ACTIVE' || existing.status === 'PAST_DUE')) {
        throw new ConflictException('Người dùng đã có subscription đang hoạt động');
      }

      // Fetch plan
      const plan = await this.prisma.plan.findFirst({
        where: { tier: command.planTier, isActive: true },
      });
      if (!plan) {
        throw new NotFoundException('Plan', command.planTier);
      }

      // Calculate period
      const now = new Date();
      const periodEnd = new Date(now);
      if (command.billingCycle === 'yearly') {
        periodEnd.setFullYear(periodEnd.getFullYear() + 1);
      } else {
        periodEnd.setMonth(periodEnd.getMonth() + 1);
      }

      const subscriptionId = createId();
      const subscription = SubscriptionEntity.createNew(
        subscriptionId,
        command.userId,
        plan.id,
        command.planTier,
        now,
        periodEnd,
      );

      await this.subscriptionRepo.save(subscription);

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

      this.logger.log(
        `Subscription created: id=${subscriptionId}, user=${command.userId}, tier=${command.planTier}`,
        'CreateSubscriptionHandler',
      );

      return {
        subscriptionId,
        planTier: command.planTier,
        status: 'ACTIVE',
        currentPeriodStart: now,
        currentPeriodEnd: periodEnd,
      };
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to tạo subscription: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined,
        this.constructor.name,
      );
      throw new InternalServerErrorException('Không thể tạo gói đăng ký. Vui lòng thử lại sau.');
    }
  }
}
