import { NextResponse } from 'next/server'; import { getServerSession } from 'next-auth'; import { authOptions } from '@/app/api/auth/[...nextauth]/route'; import { getEmails } from '@/lib/services/email-service'; import { getCachedEmailList, cacheEmailList, invalidateFolderCache } from '@/lib/redis'; import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); // Simple in-memory cache (will be removed in a future update) interface EmailCacheEntry { data: any; timestamp: number; } // Cache for 1 minute only const CACHE_TTL = 60 * 1000; const emailListCache: Record = {}; export async function GET(request: Request) { try { // Authenticate user const session = await getServerSession(authOptions); if (!session || !session.user?.id) { return NextResponse.json( { error: "Not authenticated" }, { status: 401 } ); } // Extract query parameters const { searchParams } = new URL(request.url); const page = parseInt(searchParams.get("page") || "1"); const perPage = parseInt(searchParams.get("perPage") || "20"); const folder = searchParams.get("folder") || "INBOX"; const searchQuery = searchParams.get("search") || ""; const accountId = searchParams.get("accountId") || ""; const checkOnly = searchParams.get("checkOnly") === "true"; // CRITICAL FIX: Log exact parameters received by the API console.log(`[API] Received request with: folder=${folder}, accountId=${accountId}, page=${page}, checkOnly=${checkOnly}`); // CRITICAL FIX: More robust parameter normalization // 1. If folder contains an account prefix, extract it but DO NOT use it // 2. Always prioritize the explicit accountId parameter let normalizedFolder = folder; let effectiveAccountId = accountId || 'default'; if (folder.includes(':')) { const parts = folder.split(':'); const folderAccountId = parts[0]; normalizedFolder = parts[1]; console.log(`[API] Folder has prefix (${folderAccountId}), normalized to ${normalizedFolder}`); // We intentionally DO NOT use folderAccountId here - the explicit accountId parameter takes precedence } // CRITICAL FIX: Enhanced logging for parameter resolution console.log(`[API] Using normalized parameters: folder=${normalizedFolder}, accountId=${effectiveAccountId}`); // Try to get from Redis cache first, but only if it's not a search query and not checkOnly if (!searchQuery && !checkOnly) { // CRITICAL FIX: Use consistent cache key format with the correct account ID console.log(`[API] Checking Redis cache for ${session.user.id}:${effectiveAccountId}:${normalizedFolder}:${page}:${perPage}`); const cachedEmails = await getCachedEmailList( session.user.id, effectiveAccountId, // Use effective account ID for consistent cache key normalizedFolder, // Use normalized folder name without prefix page, perPage ); if (cachedEmails) { console.log(`[API] Using Redis cached emails for ${session.user.id}:${effectiveAccountId}:${normalizedFolder}:${page}:${perPage}`); return NextResponse.json(cachedEmails); } } console.log(`[API] Redis cache miss for ${session.user.id}:${effectiveAccountId}:${normalizedFolder}:${page}:${perPage}, fetching emails from IMAP`); // Use the email service to fetch emails with the normalized folder and effective account ID // CRITICAL FIX: Pass parameters in the correct order and with proper values const emailsResult = await getEmails( session.user.id, // userId normalizedFolder, // folder (without prefix) page, // page perPage, // perPage effectiveAccountId, // accountId checkOnly // checkOnly flag - only check for new emails without loading full content ); // CRITICAL FIX: Log when emails are returned from IMAP console.log(`[API] Successfully fetched ${emailsResult.emails.length} emails from IMAP for account ${effectiveAccountId}`); // The result is already cached in the getEmails function (if not checkOnly) return NextResponse.json(emailsResult); } catch (error: any) { console.error("[API] Error fetching emails:", error); return NextResponse.json( { error: "Failed to fetch emails", message: error.message }, { status: 500 } ); } } export async function POST(request: Request) { try { const session = await getServerSession(authOptions); if (!session?.user?.id) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const { emailId, folderName, accountId } = await request.json(); if (!emailId) { return NextResponse.json({ error: 'Missing emailId parameter' }, { status: 400 }); } // Use account ID or default if not provided const effectiveAccountId = accountId || 'default'; // Normalize folder name by removing account prefix if present const normalizedFolder = folderName && folderName.includes(':') ? folderName.split(':')[1] : folderName; // Log the cache invalidation operation console.log(`Invalidating cache for user ${session.user.id}, account ${effectiveAccountId}, folder ${normalizedFolder || 'all folders'}`); // Invalidate Redis cache for the folder if (normalizedFolder) { await invalidateFolderCache(session.user.id, effectiveAccountId, normalizedFolder); } else { // If no folder specified, invalidate all folders (using a wildcard pattern) const folders = ['INBOX', 'Sent', 'Drafts', 'Trash', 'Junk']; for (const folder of folders) { await invalidateFolderCache(session.user.id, effectiveAccountId, folder); } } return NextResponse.json({ success: true }); } catch (error) { console.error('Error in POST handler:', error); return NextResponse.json({ error: 'An unexpected error occurred' }, { status: 500 }); } }