import { InternalServerErrorException } from '@nestjs/common';
import { QueryHandler, type IQueryHandler } from '@nestjs/cqrs';
import { DomainException, LoggerService, PrismaService } from '@modules/shared';
import { GetFlaggedListingsQuery } from './get-flagged-listings.query';

export interface FlaggedListingItem {
  listingId: string;
  propertyTitle: string;
  sellerName: string;
  status: string;
  totalReports: number;
  reasons: string[];
  latestReportAt: string;
}

export interface FlaggedListingsResult {
  items: FlaggedListingItem[];
  total: number;
  page: number;
  limit: number;
}

@QueryHandler(GetFlaggedListingsQuery)
export class GetFlaggedListingsHandler implements IQueryHandler<GetFlaggedListingsQuery> {
  constructor(
    private readonly prisma: PrismaService,
    private readonly logger: LoggerService,
  ) {}

  async execute(query: GetFlaggedListingsQuery): Promise<FlaggedListingsResult> {
    try {
      const { page, limit } = query;
      const skip = (page - 1) * limit;

      // Get listings that have pending flags, grouped by listing
      const flaggedListings = await this.prisma.listingFlag.groupBy({
        by: ['listingId'],
        where: { status: 'PENDING' },
        _count: { id: true },
        _max: { createdAt: true },
        orderBy: { _count: { id: 'desc' } },
        skip,
        take: limit,
      });

      const totalGroups = await this.prisma.listingFlag.groupBy({
        by: ['listingId'],
        where: { status: 'PENDING' },
      });
      const total = totalGroups.length;

      if (flaggedListings.length === 0) {
        return { items: [], total: 0, page, limit };
      }

      const listingIds = flaggedListings.map((f) => f.listingId);

      // Fetch listing details
      const listings = await this.prisma.listing.findMany({
        where: { id: { in: listingIds } },
        select: {
          id: true,
          status: true,
          property: { select: { title: true } },
          seller: { select: { fullName: true } },
        },
      });

      const listingMap = new Map(listings.map((l) => [l.id, l]));

      // Fetch distinct reasons per listing
      const reasonFlags = await this.prisma.listingFlag.findMany({
        where: { listingId: { in: listingIds }, status: 'PENDING' },
        select: { listingId: true, reason: true },
        distinct: ['listingId', 'reason'],
      });

      const reasonMap = new Map<string, string[]>();
      for (const rf of reasonFlags) {
        const arr = reasonMap.get(rf.listingId) ?? [];
        arr.push(rf.reason);
        reasonMap.set(rf.listingId, arr);
      }

      const items: FlaggedListingItem[] = flaggedListings.map((group) => {
        const listing = listingMap.get(group.listingId);
        return {
          listingId: group.listingId,
          propertyTitle: listing?.property?.title ?? 'Unknown',
          sellerName: listing?.seller?.fullName ?? 'Unknown',
          status: listing?.status ?? 'UNKNOWN',
          totalReports: group._count.id,
          reasons: reasonMap.get(group.listingId) ?? [],
          latestReportAt: group._max.createdAt?.toISOString() ?? '',
        };
      });

      return { items, total, page, limit };
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to get flagged listings: ${error instanceof Error ? error.message : String(error)}`,
        error instanceof Error ? error.stack : undefined,
        'GetFlaggedListingsHandler',
      );
      throw new InternalServerErrorException('Lỗi khi lấy danh sách tin bị báo cáo');
    }
  }
}
