import type { Metadata } from "next";
import { headers } from "next/headers";
import { auth } from "@/lib/auth/server";
import {
  db,
  collections,
  users,
  collectionFavorites,
  collectionRecipes,
  eq,
  desc,
  sql,
  and,
  gte,
  count,
  inArray,
} from "@epicure/db";
import { ExploreCollectionsContent } from "@/components/collections/explore-collections-content";

export const metadata: Metadata = {};

export type CollectionResult = {
  id: string;
  name: string;
  description: string | null;
  authorName: string | null;
  recipeCount: number;
  starCount: number;
  starred: boolean;
};

export default async function ExploreCollectionsPage() {
  const session = await auth.api.getSession({ headers: await headers() });
  if (!session) return null;

  const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);

  const trendingRows = await db
    .select({
      id: collections.id,
      name: collections.name,
      description: collections.description,
      authorName: users.name,
      recentStars: count(collectionFavorites.collectionId),
    })
    .from(collections)
    .innerJoin(users, eq(collections.userId, users.id))
    .leftJoin(
      collectionFavorites,
      and(eq(collectionFavorites.collectionId, collections.id), gte(collectionFavorites.createdAt, sevenDaysAgo))
    )
    .where(eq(collections.isPublic, true))
    .groupBy(collections.id, users.id)
    .orderBy(desc(sql`count(${collectionFavorites.collectionId})`))
    .limit(12);

  const recentRows = await db
    .select({
      id: collections.id,
      name: collections.name,
      description: collections.description,
      authorName: users.name,
    })
    .from(collections)
    .innerJoin(users, eq(collections.userId, users.id))
    .where(eq(collections.isPublic, true))
    .orderBy(desc(collections.createdAt))
    .limit(12);

  const allIds = [...new Set([...trendingRows.map((r) => r.id), ...recentRows.map((r) => r.id)])];

  const [recipeCounts, totalStars, myStars] = await Promise.all([
    allIds.length > 0
      ? db.select({ collectionId: collectionRecipes.collectionId, n: count() })
          .from(collectionRecipes)
          .where(inArray(collectionRecipes.collectionId, allIds))
          .groupBy(collectionRecipes.collectionId)
      : [],
    allIds.length > 0
      ? db.select({ collectionId: collectionFavorites.collectionId, n: count() })
          .from(collectionFavorites)
          .where(inArray(collectionFavorites.collectionId, allIds))
          .groupBy(collectionFavorites.collectionId)
      : [],
    allIds.length > 0
      ? db.query.collectionFavorites.findMany({
          where: and(eq(collectionFavorites.userId, session.user.id), inArray(collectionFavorites.collectionId, allIds)),
          columns: { collectionId: true },
        })
      : [],
  ]);

  const recipeCountMap = new Map(recipeCounts.map((r) => [r.collectionId, r.n]));
  const starCountMap = new Map(totalStars.map((r) => [r.collectionId, r.n]));
  const starredSet = new Set(myStars.map((s) => s.collectionId));

  function toResult(row: { id: string; name: string; description: string | null; authorName: string | null }): CollectionResult {
    return {
      id: row.id,
      name: row.name,
      description: row.description,
      authorName: row.authorName,
      recipeCount: recipeCountMap.get(row.id) ?? 0,
      starCount: starCountMap.get(row.id) ?? 0,
      starred: starredSet.has(row.id),
    };
  }

  const trending = trendingRows.map(toResult);
  const recent = recentRows.map(toResult);

  return <ExploreCollectionsContent trending={trending} recent={recent} />;
}
