import { Inject } from '@nestjs/common';
import { CommandHandler, type ICommandHandler } from '@nestjs/cqrs';
import { type PrismaService, type LoggerService } from '@modules/shared';
import {
  AGENT_REPOSITORY,
  type IAgentRepository,
} from '../../../domain/repositories/agent.repository';
import { QualityScoreCalculator } from '../../../domain/services/quality-score.service';
import { RecalculateQualityScoreCommand } from './recalculate-quality-score.command';

@CommandHandler(RecalculateQualityScoreCommand)
export class RecalculateQualityScoreHandler
  implements ICommandHandler<RecalculateQualityScoreCommand>
{
  constructor(
    @Inject(AGENT_REPOSITORY)
    private readonly agentRepo: IAgentRepository,
    private readonly prisma: PrismaService,
    private readonly logger: LoggerService,
  ) {}

  async execute(command: RecalculateQualityScoreCommand): Promise<void> {
    const agent = await this.agentRepo.findById(command.agentId);
    if (!agent) {
      this.logger.warn(`Agent ${command.agentId} not found, skipping recalculation`, 'RecalculateQualityScoreHandler');
      return;
    }

    // Fetch review stats for this agent
    const reviewStats = await this.prisma.review.aggregate({
      where: { targetType: 'AGENT', targetId: command.agentId },
      _avg: { rating: true },
      _count: { rating: true },
    });

    const avgRating = reviewStats._avg.rating ?? 0;
    const totalReviews = reviewStats._count.rating;

    // Fetch lead conversion rate
    const [totalLeads, convertedLeads] = await Promise.all([
      this.prisma.lead.count({ where: { agentId: command.agentId } }),
      this.prisma.lead.count({
        where: { agentId: command.agentId, status: 'CONVERTED' },
      }),
    ]);
    const conversionRate = totalLeads > 0 ? convertedLeads / totalLeads : 0;

    // Fetch listing activity ratio
    const [totalListings, activeListings] = await Promise.all([
      this.prisma.listing.count({
        where: { agentId: command.agentId },
      }),
      this.prisma.listing.count({
        where: { agentId: command.agentId, status: 'ACTIVE' },
      }),
    ]);
    const activeListingRatio =
      totalListings > 0 ? activeListings / totalListings : 0;

    // Fetch response time from agent record
    const agentRecord = await this.prisma.agent.findUnique({
      where: { id: command.agentId },
      select: { responseTimeAvg: true },
    });

    const score = QualityScoreCalculator.calculate({
      avgRating,
      totalReviews,
      responseTimeAvg: agentRecord?.responseTimeAvg ?? null,
      conversionRate,
      activeListingRatio,
    });

    await this.agentRepo.updateQualityScore(command.agentId, score);

    this.logger.log(
      `Quality score recalculated for agent ${command.agentId}: ${score} ` +
        `(rating=${avgRating.toFixed(2)}, reviews=${totalReviews}, ` +
        `conversion=${(conversionRate * 100).toFixed(1)}%, ` +
        `activeListings=${activeListings}/${totalListings})`,
      'RecalculateQualityScoreHandler',
    );
  }
}
