import { Inject, InternalServerErrorException } from '@nestjs/common';
import { CommandHandler, EventBus, type ICommandHandler } from '@nestjs/cqrs';
import { type PlanTier } from '@prisma/client';
import { DomainException, NotFoundException, ValidationException, PrismaService, LoggerService } from '@modules/shared';
import { SUBSCRIPTION_REPOSITORY, type ISubscriptionRepository } from '@modules/subscriptions';
import { SubscriptionAdjustedEvent } from '../../../domain/events/subscription-adjusted.event';
import { AdjustSubscriptionCommand } from './adjust-subscription.command';

const VALID_TIERS: PlanTier[] = ['FREE', 'AGENT_PRO', 'INVESTOR', 'ENTERPRISE'];

export interface AdjustSubscriptionResult {
  subscriptionId: string;
  newPlanTier: string;
  message: string;
}

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

  async execute(command: AdjustSubscriptionCommand): Promise<AdjustSubscriptionResult> {
    try {
      const tier = command.newPlanTier as PlanTier;
      if (!VALID_TIERS.includes(tier)) {
        throw new ValidationException(`Gói không hợp lệ: ${command.newPlanTier}`, {
          validTiers: VALID_TIERS,
        });
      }

      const subscription = await this.subscriptionRepo.findByUserId(command.userId);
      if (!subscription) {
        throw new NotFoundException('Người dùng chưa có subscription');
      }

      const newPlan = await this.prisma.plan.findUnique({
        where: { tier },
      });
      if (!newPlan) {
        throw new NotFoundException(`Gói ${tier} không tồn tại trong hệ thống`);
      }

      if (subscription.planId === newPlan.id) {
        throw new ValidationException('Người dùng đã đang sử dụng gói này', {
          currentPlanId: subscription.planId,
        });
      }

      const upgradeResult = subscription.upgrade(newPlan.id, tier);
      if (upgradeResult.isErr) {
        throw upgradeResult.unwrapErr();
      }
      await this.subscriptionRepo.update(subscription);

      this.eventBus.publish(
        new SubscriptionAdjustedEvent(subscription.id, command.adminId, newPlan.id, command.reason),
      );

      return {
        subscriptionId: subscription.id,
        newPlanTier: tier,
        message: `Subscription đã được chuyển sang gói ${tier}`,
      };
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to adjust subscription for user ${command.userId}: ${error instanceof Error ? error.message : String(error)}`,
        error instanceof Error ? error.stack : undefined,
        'AdjustSubscriptionHandler',
      );
      throw new InternalServerErrorException('Lỗi khi điều chỉnh subscription');
    }
  }
}
