import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'; import path from 'path'; export type SavedFoodReview = { id: string; userEmail: string; submissionId: string; campaignSlug: string; placeName: string; dishName: string; privacy: 'private' | 'public'; createdAt: number; }; const LOCAL_DATA_DIR = path.join(process.cwd(), '.local-review-data'); const USER_REVIEWS_FILE = path.join(LOCAL_DATA_DIR, 'user-reviews.json'); function ensureLocalDir() { mkdirSync(LOCAL_DATA_DIR, { recursive: true }); } function readAllReviews(): SavedFoodReview[] { if (!existsSync(USER_REVIEWS_FILE)) return []; try { const parsed = JSON.parse(readFileSync(USER_REVIEWS_FILE, 'utf8')) as unknown; if (!Array.isArray(parsed)) return []; return parsed.filter(isSavedReview); } catch { return []; } } function writeAllReviews(reviews: SavedFoodReview[]) { ensureLocalDir(); writeFileSync(USER_REVIEWS_FILE, `${JSON.stringify(reviews, null, 2)}\n`, 'utf8'); } function isSavedReview(value: unknown): value is SavedFoodReview { const maybe = value as Partial; return ( typeof maybe.id === 'string' && typeof maybe.userEmail === 'string' && typeof maybe.submissionId === 'string' && typeof maybe.campaignSlug === 'string' && typeof maybe.placeName === 'string' && typeof maybe.dishName === 'string' && (maybe.privacy === 'private' || maybe.privacy === 'public') && typeof maybe.createdAt === 'number' ); } function reviewId(userEmail: string, submissionId: string) { return `${userEmail.toLowerCase()}:${submissionId}`; } export function saveReviewForUser(input: { userEmail: string; submissionId: string; campaignSlug: string; placeName?: string | null; dishName?: string | null; }) { const userEmail = input.userEmail.trim().toLowerCase(); if (!userEmail || !input.submissionId) return null; const reviews = readAllReviews(); const id = reviewId(userEmail, input.submissionId); const existingIndex = reviews.findIndex((review) => review.id === id); const review: SavedFoodReview = { id, userEmail, submissionId: input.submissionId, campaignSlug: input.campaignSlug, placeName: input.placeName?.trim() || 'Foodstar review', dishName: input.dishName?.trim() || 'Micro food review', privacy: 'private', createdAt: existingIndex >= 0 ? reviews[existingIndex]!.createdAt : Date.now(), }; if (existingIndex >= 0) reviews[existingIndex] = review; else reviews.push(review); writeAllReviews(reviews); return review; } export function listReviewsForUser(userEmail: string) { const normalized = userEmail.trim().toLowerCase(); return readAllReviews() .filter((review) => review.userEmail === normalized) .sort((a, b) => b.createdAt - a.createdAt); }