const mongoose = require('mongoose'); // Schema für Aufgaben const taskSchema = new mongoose.Schema({ title: { type: String, required: true, trim: true, maxlength: 100 }, description: { type: String, trim: true, maxlength: 500 }, icon: { type: String, default: 'task', enum: [ 'task', 'clean', 'dishes', 'vacuum', 'trash', 'bed', 'homework', 'teeth', 'shower', 'clothes', 'toys', 'pets', 'garden', 'help', 'read', 'practice', 'exercise', 'cook', 'organize', 'other' ] }, points: { type: Number, required: true, min: 1, max: 500, default: 10 }, difficulty: { type: String, enum: ['easy', 'medium', 'hard'], default: 'easy' }, category: { type: String, enum: [ 'household', 'personal', 'homework', 'chores', 'hygiene', 'pets', 'garden', 'helping', 'learning', 'exercise', 'other' ], default: 'household' }, assignedTo: { type: mongoose.Schema.Types.ObjectId, ref: 'Child', required: true }, createdBy: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }, dueDate: { type: Date, required: true }, status: { type: String, enum: ['pending', 'completed', 'approved', 'rejected'], default: 'pending' }, completedAt: { type: Date }, approvedAt: { type: Date }, approvedBy: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }, rejectionReason: { type: String, trim: true, maxlength: 200 }, recurring: { isRecurring: { type: Boolean, default: false }, frequency: { type: String, enum: ['daily', 'weekly', 'monthly'], required: function() { return this.recurring.isRecurring; } }, daysOfWeek: [{ type: Number, min: 0, max: 6 // 0 = Sonntag, 6 = Samstag }], endDate: Date, nextDueDate: Date }, priority: { type: String, enum: ['low', 'normal', 'high', 'urgent'], default: 'normal' }, estimatedTime: { type: Number, // in Minuten min: 1, max: 480 // max 8 Stunden }, tags: [{ type: String, trim: true, maxlength: 20 }], notes: { type: String, trim: true, maxlength: 1000 }, attachments: [{ filename: String, url: String, uploadedAt: { type: Date, default: Date.now } }], isActive: { type: Boolean, default: true }, createdAt: { type: Date, default: Date.now }, updatedAt: { type: Date, default: Date.now } }); // Indizes für bessere Performance taskSchema.index({ assignedTo: 1, status: 1, dueDate: 1 }); taskSchema.index({ createdBy: 1, createdAt: -1 }); taskSchema.index({ dueDate: 1, status: 1 }); taskSchema.index({ 'recurring.isRecurring': 1, 'recurring.nextDueDate': 1 }); // Middleware: updatedAt automatisch setzen taskSchema.pre('save', function(next) { this.updatedAt = new Date(); next(); }); // Methode: Aufgabe als erledigt markieren taskSchema.methods.markCompleted = function() { this.status = 'completed'; this.completedAt = new Date(); return this.save(); }; // Methode: Aufgabe genehmigen taskSchema.methods.approve = async function(approvedByUserId) { this.status = 'approved'; this.approvedAt = new Date(); this.approvedBy = approvedByUserId; // Punkte dem Kind gutschreiben const Child = mongoose.model('Child'); const child = await Child.findById(this.assignedTo); if (child) { await child.addPoints(this.points); // Statistiken aktualisieren child.stats.tasksCompleted += 1; child.stats.tasksCompletedToday += 1; child.updateStreak(); await child.save(); } // Nächste wiederkehrende Aufgabe erstellen if (this.recurring.isRecurring) { await this.createNextRecurringTask(); } return this.save(); }; // Methode: Aufgabe ablehnen taskSchema.methods.reject = function(reason, rejectedByUserId) { this.status = 'rejected'; this.rejectionReason = reason; this.approvedBy = rejectedByUserId; return this.save(); }; // Methode: Nächste wiederkehrende Aufgabe erstellen taskSchema.methods.createNextRecurringTask = async function() { if (!this.recurring.isRecurring) return; const Task = mongoose.model('Task'); let nextDueDate = new Date(this.dueDate); // Nächstes Fälligkeitsdatum berechnen switch (this.recurring.frequency) { case 'daily': nextDueDate.setDate(nextDueDate.getDate() + 1); break; case 'weekly': nextDueDate.setDate(nextDueDate.getDate() + 7); break; case 'monthly': nextDueDate.setMonth(nextDueDate.getMonth() + 1); break; } // Prüfen ob End-Datum erreicht if (this.recurring.endDate && nextDueDate > this.recurring.endDate) { return; } // Neue Aufgabe erstellen const newTask = new Task({ title: this.title, description: this.description, icon: this.icon, points: this.points, difficulty: this.difficulty, category: this.category, assignedTo: this.assignedTo, createdBy: this.createdBy, dueDate: nextDueDate, recurring: this.recurring, priority: this.priority, estimatedTime: this.estimatedTime, tags: this.tags, notes: this.notes }); await newTask.save(); }; // Statische Methode: Überfällige Aufgaben finden taskSchema.statics.findOverdue = function() { const now = new Date(); return this.find({ dueDate: { $lt: now }, status: { $in: ['pending', 'completed'] }, isActive: true }); }; // Statische Methode: Heutige Aufgaben für ein Kind taskSchema.statics.findTodayTasks = function(childId) { const today = new Date(); today.setHours(0, 0, 0, 0); const tomorrow = new Date(today); tomorrow.setDate(tomorrow.getDate() + 1); return this.find({ assignedTo: childId, dueDate: { $gte: today, $lt: tomorrow }, isActive: true }).sort({ priority: -1, createdAt: 1 }); }; // Virtuelle Eigenschaft: Ist überfällig taskSchema.virtual('isOverdue').get(function() { return this.dueDate < new Date() && this.status === 'pending'; }); // Virtuelle Eigenschaft: Ist heute fällig taskSchema.virtual('isDueToday').get(function() { const today = new Date(); today.setHours(0, 0, 0, 0); const tomorrow = new Date(today); tomorrow.setDate(tomorrow.getDate() + 1); return this.dueDate >= today && this.dueDate < tomorrow; }); module.exports = mongoose.model('Task', taskSchema);