import { ForbiddenException, Inject } from '@nestjs/common';
import { type IQueryHandler, QueryHandler } from '@nestjs/cqrs';
import { NotFoundException, PrismaService } from '@modules/shared';
import {
  PROJECT_REPOSITORY,
  type IProjectRepository,
} from '../../../domain/repositories/project-development.repository';
import { GetProjectStatsQuery } from './get-project-stats.query';

export interface ProjectStats {
  projectId: string;
  linkedListingCount: number;
  activeListingCount: number;
  totalInquiries: number;
  unreadInquiries: number;
  savedByUsers: number;
}

interface StatsRow {
  linked: bigint;
  active: bigint;
  inquiries: bigint;
  unread: bigint;
  saves: bigint;
}

/**
 * Aggregates project-level metrics for the "Dự án của tôi" dashboard.
 * Visible to ADMIN (any project) and DEVELOPER (only projects they own).
 */
@QueryHandler(GetProjectStatsQuery)
export class GetProjectStatsHandler
  implements IQueryHandler<GetProjectStatsQuery, ProjectStats>
{
  constructor(
    @Inject(PROJECT_REPOSITORY)
    private readonly projectRepo: IProjectRepository,
    private readonly prisma: PrismaService,
  ) {}

  async execute(query: GetProjectStatsQuery): Promise<ProjectStats> {
    const project = await this.projectRepo.findById(query.projectId);
    if (!project) {
      throw new NotFoundException('Dự án', query.projectId);
    }

    if (query.requesterRole !== 'ADMIN') {
      if (
        query.requesterRole !== 'DEVELOPER' ||
        project.ownerId !== query.requesterUserId
      ) {
        throw new ForbiddenException('Bạn không có quyền xem thống kê dự án này');
      }
    }

    // Single-round-trip aggregate pulling listing + inquiry + savedListing
    // counts via the Property link.
    const rows = await this.prisma.$queryRaw<StatsRow[]>`
      SELECT
        COUNT(DISTINCT l.id) FILTER (WHERE l.id IS NOT NULL) AS linked,
        COUNT(DISTINCT l.id) FILTER (WHERE l.status = 'ACTIVE') AS active,
        COUNT(DISTINCT i.id) FILTER (WHERE i.id IS NOT NULL) AS inquiries,
        COUNT(DISTINCT i.id) FILTER (WHERE i.id IS NOT NULL AND i."isRead" = FALSE) AS unread,
        COUNT(DISTINCT sl."userId") FILTER (WHERE sl."userId" IS NOT NULL) AS saves
      FROM "Property" p
      LEFT JOIN "Listing" l ON l."propertyId" = p.id
      LEFT JOIN "Inquiry" i ON i."listingId" = l.id
      LEFT JOIN "SavedListing" sl ON sl."listingId" = l.id
      WHERE p."projectDevelopmentId" = ${query.projectId}
    `;

    const row = rows[0] ?? {
      linked: BigInt(0),
      active: BigInt(0),
      inquiries: BigInt(0),
      unread: BigInt(0),
      saves: BigInt(0),
    };

    return {
      projectId: query.projectId,
      linkedListingCount: Number(row.linked),
      activeListingCount: Number(row.active),
      totalInquiries: Number(row.inquiries),
      unreadInquiries: Number(row.unread),
      savedByUsers: Number(row.saves),
    };
  }
}
