import { type PrismaService } from '@modules/shared';
import {
  type DashboardStats,
  type RevenueStatsItem,
} from '../../domain/repositories/admin-query.repository';

export async function getDashboardStats(prisma: PrismaService): Promise<DashboardStats> {
  const thirtyDaysAgo = new Date();
  thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

  const [
    totalUsers,
    totalListings,
    activeListings,
    pendingModerationCount,
    totalAgents,
    verifiedAgents,
    totalTransactions,
    newUsersLast30Days,
    newListingsLast30Days,
  ] = await Promise.all([
    prisma.user.count(),
    prisma.listing.count(),
    prisma.listing.count({ where: { status: 'ACTIVE' } }),
    prisma.listing.count({ where: { status: 'PENDING_REVIEW' } }),
    prisma.agent.count(),
    prisma.agent.count({ where: { isVerified: true } }),
    prisma.transaction.count(),
    prisma.user.count({ where: { createdAt: { gte: thirtyDaysAgo } } }),
    prisma.listing.count({ where: { createdAt: { gte: thirtyDaysAgo } } }),
  ]);

  return {
    totalUsers,
    totalListings,
    activeListings,
    pendingModerationCount,
    totalAgents,
    verifiedAgents,
    totalTransactions,
    newUsersLast30Days,
    newListingsLast30Days,
  };
}

export async function getRevenueStats(
  prisma: PrismaService,
  startDate: Date,
  endDate: Date,
  groupBy: 'day' | 'month',
): Promise<RevenueStatsItem[]> {
  const payments = await prisma.payment.findMany({
    where: {
      status: 'COMPLETED',
      createdAt: { gte: startDate, lte: endDate },
    },
    select: {
      type: true,
      amountVND: true,
      createdAt: true,
    },
    orderBy: { createdAt: 'asc' },
  });

  const grouped = new Map<string, {
    totalRevenue: bigint;
    subscriptionRevenue: bigint;
    listingFeeRevenue: bigint;
    featuredListingRevenue: bigint;
    transactionCount: number;
  }>();

  for (const payment of payments) {
    const period = groupBy === 'day'
      ? payment.createdAt.toISOString().slice(0, 10)
      : payment.createdAt.toISOString().slice(0, 7);

    if (!grouped.has(period)) {
      grouped.set(period, {
        totalRevenue: 0n,
        subscriptionRevenue: 0n,
        listingFeeRevenue: 0n,
        featuredListingRevenue: 0n,
        transactionCount: 0,
      });
    }

    const stats = grouped.get(period)!;
    stats.totalRevenue += payment.amountVND;
    stats.transactionCount++;

    switch (payment.type) {
      case 'SUBSCRIPTION':
        stats.subscriptionRevenue += payment.amountVND;
        break;
      case 'LISTING_FEE':
        stats.listingFeeRevenue += payment.amountVND;
        break;
      case 'FEATURED_LISTING':
        stats.featuredListingRevenue += payment.amountVND;
        break;
    }
  }

  return Array.from(grouped.entries()).map(([period, stats]) => ({
    period,
    ...stats,
  }));
}
