import { InternalServerErrorException } from '@nestjs/common';
import { type IQueryHandler, QueryHandler } from '@nestjs/cqrs';
import { type Plan } from '@prisma/client';
import { DomainException, CacheService, CachePrefix, CacheTTL, NotFoundException, PrismaService, LoggerService } from '@modules/shared';
import { GetPlanQuery } from './get-plan.query';

export interface PlanDto {
  id: string;
  tier: string;
  name: string;
  priceMonthlyVND: string;
  priceYearlyVND: string;
  maxListings: number | null;
  maxSavedSearches: number | null;
  features: unknown;
  isActive: boolean;
}

@QueryHandler(GetPlanQuery)
export class GetPlanHandler implements IQueryHandler<GetPlanQuery> {
  constructor(
    private readonly prisma: PrismaService,
    private readonly cacheService: CacheService,
    private readonly logger: LoggerService,
  ) {}

  async execute(query: GetPlanQuery): Promise<PlanDto | PlanDto[]> {
    try {
      if (query.planTier) {
        const cacheKey = CacheService.buildKey(CachePrefix.PLAN_LIST, query.planTier);
        return this.cacheService.getOrSet(
          cacheKey,
          async () => {
            const plan = await this.prisma.plan.findFirst({
              where: { tier: query.planTier, isActive: true },
            });
            if (!plan) throw new NotFoundException('Plan', query.planTier);
            return this.toDto(plan);
          },
          CacheTTL.PLAN_LIST,
          'plan',
        );
      }

      const cacheKey = CacheService.buildKey(CachePrefix.PLAN_LIST, 'all');
      return this.cacheService.getOrSet(
        cacheKey,
        async () => {
          const plans = await this.prisma.plan.findMany({
            where: { isActive: true },
            orderBy: { priceMonthlyVND: 'asc' },
          });
          return plans.map((p) => this.toDto(p));
        },
        CacheTTL.PLAN_LIST,
        'plan',
      );
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to truy vấn thông tin gói dịch vụ: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined,
        this.constructor.name,
      );
      throw new InternalServerErrorException('Không thể truy vấn thông tin gói dịch vụ. Vui lòng thử lại sau.');
    }
  }

  private toDto(plan: Plan): PlanDto {
    return {
      id: plan.id,
      tier: plan.tier,
      name: plan.name,
      priceMonthlyVND: plan.priceMonthlyVND.toString(),
      priceYearlyVND: plan.priceYearlyVND.toString(),
      maxListings: plan.maxListings,
      maxSavedSearches: plan.maxSavedSearches,
      features: plan.features,
      isActive: plan.isActive,
    };
  }
}
