import { getUserIdFromSession } from '../../../utils/auth'; import { REWARDS } from '../../../utils/economy'; import prisma from '../../../utils/prisma'; import { applyStreakMultiplier } from '../../../utils/streak'; interface CompletionResponse { message: string; reward: { coins: number; exp: number; }; updatedCoins: number; updatedExp: number; } // Helper to get the start of the day in UTC function getStartOfDay(date: Date): Date { const d = new Date(date); d.setUTCHours(0, 0, 0, 0); return d; } export default defineEventHandler(async (event): Promise => { const userId = await getUserIdFromSession(event); const habitId = parseInt(event.context.params?.id || '', 10); if (isNaN(habitId)) { throw createError({ statusCode: 400, statusMessage: 'Invalid habit ID.' }); } // Fetch user and habit in parallel const [user, habit] = await Promise.all([ prisma.user.findUnique({ where: { id: userId } }), prisma.habit.findFirst({ where: { id: habitId, userId } }) ]); if (!user) { throw createError({ statusCode: 401, statusMessage: 'User not found.' }); } if (!habit) { throw createError({ statusCode: 404, statusMessage: 'Habit not found.' }); } const today = new Date(); const jsDayOfWeek = today.getDay(); // 0 (Sunday) to 6 (Saturday) // Convert JS day (Sun=0) to the application's convention (Mon=0, Sun=6) const appDayOfWeek = (jsDayOfWeek === 0) ? 6 : jsDayOfWeek - 1; if (!(habit.daysOfWeek as number[]).includes(appDayOfWeek)) { throw createError({ statusCode: 400, statusMessage: 'Habit is not active today.' }); } const startOfToday = getStartOfDay(today); const existingCompletion = await prisma.habitCompletion.findFirst({ where: { habitId: habitId, date: startOfToday, }, }); if (existingCompletion) { throw createError({ statusCode: 409, statusMessage: 'Habit already completed today.' }); } // Apply the streak multiplier to the base reward const baseReward = REWARDS.HABITS.COMPLETION; const finalReward = applyStreakMultiplier(baseReward, user.dailyStreak); const village = await prisma.village.findUnique({ where: { userId } }); const [, updatedUser] = await prisma.$transaction([ prisma.habitCompletion.create({ data: { habitId: habitId, date: startOfToday, }, }), prisma.user.update({ where: { id: userId }, data: { coins: { increment: finalReward.coins, }, exp: { increment: finalReward.exp, }, }, }), ...(village ? [prisma.villageEvent.create({ data: { villageId: village.id, type: 'HABIT_COMPLETION', message: `Привычка "${habit.name}" выполнена, принеся вам ${finalReward.coins} монет и ${finalReward.exp} опыта.${user.dailyStreak > 1 ? ` Ваша серия визитов (x${user.dailyStreak}) ${user.dailyStreak === 2 ? 'удвоила' : 'утроила'} награду!` : ''}`, coins: finalReward.coins, exp: finalReward.exp, } })] : []), ]); return { message: 'Habit completed successfully!', reward: finalReward, updatedCoins: updatedUser.coins, updatedExp: updatedUser.exp, }; });