import { Inject, InternalServerErrorException } from '@nestjs/common';
import { CommandHandler, EventBus, type ICommandHandler } from '@nestjs/cqrs';
import { DomainException, LoggerService } from '@modules/shared';
import {
  AGENT_REPOSITORY,
  type IAgentRepository,
} from '../../../domain/repositories/agent.repository';
import { QualityScoreCalculator } from '../../../domain/services/quality-score.service';
import { QualityScore } from '../../../domain/value-objects/quality-score.vo';
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 eventBus: EventBus,
    private readonly logger: LoggerService,
  ) {}

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

      const inputs = await this.agentRepo.getQualityScoreInputs(command.agentId);

      const rawScore = QualityScoreCalculator.calculate(inputs);
      const newScore = QualityScore.fromPersistence(rawScore);

      agent.updateQualityScore(newScore);

      await this.agentRepo.save(agent);

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

      this.logger.log(
        `Quality score recalculated for agent ${command.agentId}: ${rawScore} ` +
          `(rating=${inputs.avgRating.toFixed(2)}, reviews=${inputs.totalReviews}, ` +
          `conversion=${(inputs.conversionRate * 100).toFixed(1)}%, ` +
          `activeListingRatio=${(inputs.activeListingRatio * 100).toFixed(1)}%)`,
        'RecalculateQualityScoreHandler',
      );
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to recalculate quality score for agent ${command.agentId}: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined,
        this.constructor.name,
      );
      throw new InternalServerErrorException('Không thể tính lại điểm chất lượng môi giới');
    }
  }
}
