import { HttpStatus, InternalServerErrorException } from '@nestjs/common';
import { CommandHandler, type ICommandHandler } from '@nestjs/cqrs';
import { DomainException, ErrorCode, LoggerService, PrismaService } from '@modules/shared';
import { ReportListingCommand } from './report-listing.command';

/** Threshold: auto-flag listing for moderator review when it reaches this many reports. */
const AUTO_FLAG_THRESHOLD = 3;

export interface ReportListingResult {
  flagId: string;
  listingId: string;
  totalReports: number;
  autoFlagged: boolean;
}

@CommandHandler(ReportListingCommand)
export class ReportListingHandler implements ICommandHandler<ReportListingCommand> {
  constructor(
    private readonly prisma: PrismaService,
    private readonly logger: LoggerService,
  ) {}

  async execute(command: ReportListingCommand): Promise<ReportListingResult> {
    try {
      // Verify listing exists and is active
      const listing = await this.prisma.listing.findUnique({
        where: { id: command.listingId },
        select: { id: true, status: true },
      });

      if (!listing) {
        throw new DomainException(
          ErrorCode.NOT_FOUND,
          'Tin đăng không tồn tại',
          HttpStatus.NOT_FOUND,
        );
      }

      // Prevent self-reporting
      const isSeller = await this.prisma.listing.findFirst({
        where: { id: command.listingId, sellerId: command.reporterId },
        select: { id: true },
      });

      if (isSeller) {
        throw new DomainException(
          ErrorCode.BAD_REQUEST,
          'Không thể báo cáo tin đăng của chính mình',
          HttpStatus.BAD_REQUEST,
        );
      }

      // Check for duplicate report (unique constraint will also catch this)
      const existingFlag = await this.prisma.listingFlag.findUnique({
        where: {
          listingId_reporterId: {
            listingId: command.listingId,
            reporterId: command.reporterId,
          },
        },
      });

      if (existingFlag) {
        throw new DomainException(
          ErrorCode.CONFLICT,
          'Bạn đã báo cáo tin đăng này rồi',
          HttpStatus.CONFLICT,
        );
      }

      // Create the flag
      const flag = await this.prisma.listingFlag.create({
        data: {
          listingId: command.listingId,
          reporterId: command.reporterId,
          reason: command.reason,
          description: command.description ?? null,
        },
      });

      // Count total reports for this listing
      const totalReports = await this.prisma.listingFlag.count({
        where: { listingId: command.listingId },
      });

      // Auto-flag: when ≥3 reports, move listing to PENDING_REVIEW for moderator
      let autoFlagged = false;
      if (totalReports >= AUTO_FLAG_THRESHOLD && listing.status === 'ACTIVE') {
        await this.prisma.listing.update({
          where: { id: command.listingId },
          data: {
            status: 'PENDING_REVIEW',
            moderationNotes: `Tự động chuyển sang chờ duyệt: ${totalReports} báo cáo từ người dùng`,
          },
        });
        autoFlagged = true;
        this.logger.log(
          `Listing ${command.listingId} auto-flagged for moderation (${totalReports} reports)`,
          'ReportListingHandler',
        );
      }

      return {
        flagId: flag.id,
        listingId: command.listingId,
        totalReports,
        autoFlagged,
      };
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to report listing: ${error instanceof Error ? error.message : String(error)}`,
        error instanceof Error ? error.stack : undefined,
        'ReportListingHandler',
      );
      throw new InternalServerErrorException('Không thể báo cáo tin đăng');
    }
  }
}
