import { NextRequest, NextResponse } from "next/server";
import crypto from "node:crypto";
import {
  db,
  users,
  recipes,
  comments,
  ratings,
  userFollows,
  favorites,
  userNotificationPrefs,
  eq,
  and,
  gte,
  desc,
  count,
  sql,
} from "@epicure/db";
import { sendEmail, weeklyDigestHtml } from "@/lib/email";

// Internal cron endpoint — triggered by the `digest-cron` container on a weekly
// schedule (see compose.prod.yml). Not part of the public API surface;
// protected by a shared secret rather than user auth.
//
// Computes, for every opted-in user: new followers / new comments / new
// ratings on their recipes in the last 7 days, plus a site-wide top-3
// trending list, and emails a summary. Excludes users who turned off
// "Weekly digest" in Settings → Notifications (userNotificationPrefs.weeklyDigestEmail,
// default true — no row means opted in).

const CHUNK_SIZE = 20;

function isAuthorized(req: NextRequest): boolean {
  const secret = process.env["CRON_SECRET"];
  if (!secret) return false;

  const header = req.headers.get("authorization");
  if (!header?.startsWith("Bearer ")) return false;
  const provided = header.slice("Bearer ".length);

  const a = Buffer.from(provided);
  const b = Buffer.from(secret);
  if (a.length !== b.length) return false;
  return crypto.timingSafeEqual(a, b);
}

function chunk<T>(arr: T[], size: number): T[][] {
  const out: T[][] = [];
  for (let i = 0; i < arr.length; i += size) out.push(arr.slice(i, i + size));
  return out;
}

export async function POST(req: NextRequest) {
  if (!isAuthorized(req)) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const weekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
  const baseUrl = process.env["BETTER_AUTH_URL"] ?? "http://localhost:3000";

  const [allUsers, optedOutRows, followerRows, commentRows, ratingRows, trending] = await Promise.all([
    db.select({ id: users.id, email: users.email }).from(users),
    db
      .select({ userId: userNotificationPrefs.userId })
      .from(userNotificationPrefs)
      .where(eq(userNotificationPrefs.weeklyDigestEmail, false)),
    db
      .select({ userId: userFollows.followingId, n: count() })
      .from(userFollows)
      .where(gte(userFollows.createdAt, weekAgo))
      .groupBy(userFollows.followingId),
    db
      .select({ userId: recipes.authorId, n: count() })
      .from(comments)
      .innerJoin(recipes, eq(comments.recipeId, recipes.id))
      .where(gte(comments.createdAt, weekAgo))
      .groupBy(recipes.authorId),
    db
      .select({ userId: recipes.authorId, n: count() })
      .from(ratings)
      .innerJoin(recipes, eq(ratings.recipeId, recipes.id))
      .where(gte(ratings.createdAt, weekAgo))
      .groupBy(recipes.authorId),
    db
      .select({
        id: recipes.id,
        title: recipes.title,
        favoriteCount: sql<number>`cast(count(${favorites.recipeId}) as int)`,
      })
      .from(recipes)
      .leftJoin(
        favorites,
        and(eq(favorites.recipeId, recipes.id), gte(favorites.createdAt, weekAgo))
      )
      .where(eq(recipes.visibility, "public"))
      .groupBy(recipes.id)
      .orderBy(desc(sql`count(${favorites.recipeId})`), desc(recipes.createdAt))
      .limit(3),
  ]);

  const optedOut = new Set(optedOutRows.map((r) => r.userId));
  const recipients = allUsers.filter((u) => !optedOut.has(u.id));

  const followerMap = new Map(followerRows.map((r) => [r.userId, r.n]));
  const commentMap = new Map(commentRows.map((r) => [r.userId, r.n]));
  const ratingMap = new Map(ratingRows.map((r) => [r.userId, r.n]));
  const trendingList = trending.map((r) => ({ id: r.id, title: r.title }));

  let sent = 0;
  let failed = 0;

  for (const batch of chunk(recipients, CHUNK_SIZE)) {
    const results = await Promise.allSettled(
      batch.map((user) => {
        const newFollowers = followerMap.get(user.id) ?? 0;
        const newComments = commentMap.get(user.id) ?? 0;
        const newRatings = ratingMap.get(user.id) ?? 0;

        return sendEmail({
          to: user.email,
          subject: "Your weekly digest — Epicure",
          html: weeklyDigestHtml({
            newFollowers,
            newComments,
            newRatings,
            trending: trendingList,
            baseUrl,
          }),
        });
      })
    );

    for (const r of results) {
      if (r.status === "fulfilled") sent++;
      else failed++;
    }
  }

  return NextResponse.json({ ok: true, totalUsers: allUsers.length, optedOut: optedOut.size, sent, failed });
}
