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,
  };
}

// ---------------------------------------------------------------------------
// Simple in-process cache for revenue stats (TTL = 60 seconds)
// ---------------------------------------------------------------------------

interface RevenueCacheEntry {
  expiresAt: number;
  data: RevenueStatsItem[];
}

const revenueStatsCache = new Map<string, RevenueCacheEntry>();

function buildCacheKey(startDate: Date, endDate: Date, groupBy: string): string {
  return `${startDate.toISOString()}|${endDate.toISOString()}|${groupBy}`;
}

// Raw row returned by Postgres for the aggregation query
interface RevenueRawRow {
  period: string;
  total_revenue: bigint;
  subscription_revenue: bigint;
  listing_fee_revenue: bigint;
  featured_listing_revenue: bigint;
  transaction_count: bigint;
}

export async function getRevenueStats(
  prisma: PrismaService,
  startDate: Date,
  endDate: Date,
  groupBy: 'day' | 'month',
): Promise<RevenueStatsItem[]> {
  const cacheKey = buildCacheKey(startDate, endDate, groupBy);
  const cached = revenueStatsCache.get(cacheKey);
  if (cached && cached.expiresAt > Date.now()) {
    return cached.data;
  }

  const truncUnit = groupBy === 'day' ? 'day' : 'month';

  const rows = await prisma.$queryRaw<RevenueRawRow[]>`
    SELECT
      TO_CHAR(DATE_TRUNC(${truncUnit}, "createdAt"), 'YYYY-MM-DD') AS period,
      SUM("amountVND")                                               AS total_revenue,
      SUM(CASE WHEN type = 'SUBSCRIPTION'      THEN "amountVND" ELSE 0 END) AS subscription_revenue,
      SUM(CASE WHEN type = 'LISTING_FEE'       THEN "amountVND" ELSE 0 END) AS listing_fee_revenue,
      SUM(CASE WHEN type = 'FEATURED_LISTING'  THEN "amountVND" ELSE 0 END) AS featured_listing_revenue,
      COUNT(*)                                                       AS transaction_count
    FROM "Payment"
    WHERE status = 'COMPLETED'
      AND "createdAt" >= ${startDate}
      AND "createdAt" <= ${endDate}
    GROUP BY DATE_TRUNC(${truncUnit}, "createdAt")
    ORDER BY DATE_TRUNC(${truncUnit}, "createdAt") ASC
  `;

  const data: RevenueStatsItem[] = rows.map((row) => ({
    period: row.period,
    totalRevenue: BigInt(row.total_revenue),
    subscriptionRevenue: BigInt(row.subscription_revenue),
    listingFeeRevenue: BigInt(row.listing_fee_revenue),
    featuredListingRevenue: BigInt(row.featured_listing_revenue),
    transactionCount: Number(row.transaction_count),
  }));

  revenueStatsCache.set(cacheKey, { expiresAt: Date.now() + 60_000, data });

  return data;
}
