import { readFileSync, writeFileSync, existsSync } from 'fs'; import { dirname, join } from 'path'; import { fileURLToPath } from 'url'; const __dirname = dirname(fileURLToPath(import.meta.url)); const DB_FILE = process.env.DB_PATH || join(__dirname, 'data.json'); function loadDB() { if (existsSync(DB_FILE)) { return JSON.parse(readFileSync(DB_FILE, 'utf-8')); } return { users: [], recipes: [], invite_tokens: [], _counters: { users: 0, recipes: 0, invite_tokens: 0 } }; } function saveDB(data) { writeFileSync(DB_FILE, JSON.stringify(data, null, 2)); } let db = loadDB(); function nextId(table) { db._counters[table] = (db._counters[table] || 0) + 1; return db._counters[table]; } function now() { return new Date().toISOString().replace('T', ' ').slice(0, 19); } export function getDb() { return db; } export function getAllRecipes(search, category) { let results = [...db.recipes]; if (search) { const term = search.toLowerCase(); results = results.filter(r => (r.name && r.name.toLowerCase().includes(term)) || (r.description && r.description.toLowerCase().includes(term)) || (r.ingredients && r.ingredients.toLowerCase().includes(term)) ); } if (category && category !== 'Alle') { results = results.filter(r => r.category === category); } results.sort((a, b) => (b.created_at || '').localeCompare(a.created_at || '')); return results; } export function getRecipeById(id) { return db.recipes.find(r => r.id === Number(id)) || undefined; } export function createRecipe(recipe) { const id = nextId('recipes'); const nowStr = now(); const row = { id, name: recipe.name, description: recipe.description || '', ingredients: JSON.stringify(recipe.ingredients || []), steps: JSON.stringify(recipe.steps || []), category: recipe.category || 'Sonstiges', tiktok_url: recipe.tiktok_url || null, tiktok_author: recipe.tiktok_author || null, thumbnail_url: recipe.thumbnail_url || null, user_id: recipe.user_id || null, created_at: nowStr, updated_at: nowStr, }; db.recipes.push(row); saveDB(db); return row; } export function updateRecipe(id, recipe) { const idx = db.recipes.findIndex(r => r.id === Number(id)); if (idx === -1) return undefined; db.recipes[idx] = { ...db.recipes[idx], name: recipe.name, description: recipe.description || '', ingredients: JSON.stringify(recipe.ingredients || []), steps: JSON.stringify(recipe.steps || []), category: recipe.category || 'Sonstiges', tiktok_url: recipe.tiktok_url || null, tiktok_author: recipe.tiktok_author || null, thumbnail_url: recipe.thumbnail_url || null, updated_at: now(), }; saveDB(db); return db.recipes[idx]; } export function deleteRecipe(id) { const idx = db.recipes.findIndex(r => r.id === Number(id)); if (idx === -1) return; db.recipes.splice(idx, 1); saveDB(db); } export function getCategories() { const counts = {}; for (const r of db.recipes) { counts[r.category] = (counts[r.category] || 0) + 1; } return Object.entries(counts) .map(([category, count]) => ({ category, count })) .sort((a, b) => b.count - a.count); } export function getUserByUsername(username) { return db.users.find(u => u.username === username) || undefined; } export function getUserById(id) { return db.users.find(u => u.id === Number(id)) || undefined; } export function createUser(username, hashedPassword, isAdmin = false) { const id = nextId('users'); const user = { id, username, password: hashedPassword, is_admin: isAdmin ? 1 : 0, created_at: now(), }; db.users.push(user); saveDB(db); return { id, username, is_admin: user.is_admin, created_at: user.created_at }; } export function updateUserCredentials(userId, { username, password }) { const user = db.users.find(u => u.id === Number(userId)); if (!user) return null; if (username) user.username = username; if (password) user.password = password; saveDB(db); return { id: user.id, username: user.username, is_admin: user.is_admin, created_at: user.created_at }; } export function createInviteToken(token, createdBy) { const id = nextId('invite_tokens'); db.invite_tokens.push({ id, token, created_by: createdBy, used_by: null, created_at: now(), used_at: null, }); saveDB(db); } export function getInviteToken(token) { return db.invite_tokens.find(i => i.token === token) || undefined; } export function useInviteToken(token, userId) { const inv = db.invite_tokens.find(i => i.token === token); if (inv) { inv.used_by = userId; inv.used_at = now(); saveDB(db); } } export function getInvitesByUser(userId) { return db.invite_tokens .filter(i => i.created_by === Number(userId)) .sort((a, b) => (b.created_at || '').localeCompare(a.created_at || '')) .map(i => { const usedByUser = i.used_by ? db.users.find(u => u.id === i.used_by) : null; return { ...i, used_by_username: usedByUser ? usedByUser.username : null }; }); } export function getAllUsers() { return db.users .map(u => ({ id: u.id, username: u.username, is_admin: u.is_admin, created_at: u.created_at })) .sort((a, b) => (b.created_at || '').localeCompare(a.created_at || '')); } export function deleteUser(id) { const idx = db.users.findIndex(u => u.id === Number(id)); if (idx === -1) return false; db.users.splice(idx, 1); db.invite_tokens = db.invite_tokens.filter(i => i.created_by !== Number(id)); saveDB(db); return true; } export function getInviteStats() { const total = db.invite_tokens.length; const used = db.invite_tokens.filter(i => i.used_by !== null).length; return { total, used, available: total - used }; }