using MongoDB.Bson; using MongoDB.Driver; using QuestionsApi.Models; namespace QuestionsApi.Services; public sealed class AppFeedbackStore { private readonly IMongoCollection _feedback; public AppFeedbackStore(MongoDatabaseProvider mongo) { _feedback = mongo.Database.GetCollection("AppFeedback"); _feedback.Indexes.CreateMany([ new CreateIndexModel(Builders.IndexKeys.Ascending(value => value.Status).Descending(value => value.CreatedUtc)), new CreateIndexModel(Builders.IndexKeys.Ascending(value => value.Category).Descending(value => value.CreatedUtc)), new CreateIndexModel(Builders.IndexKeys.Ascending(value => value.UserId).Descending(value => value.CreatedUtc)) ]); } public async Task CreateAsync(string userId, CreateAppFeedbackRequest request) { var now = DateTime.UtcNow; var report = new AppFeedback { UserId = userId, Category = request.Category.Trim().ToLowerInvariant(), Details = request.Details.Trim(), Context = request.Context ?? new AppFeedbackContext(), CreatedUtc = now, UpdatedUtc = now }; await _feedback.InsertOneAsync(report); return report; } public async Task GetAsync(string id) => ObjectId.TryParse(id, out _) ? await _feedback.Find(value => value.Id == id).FirstOrDefaultAsync() : null; public async Task SearchAsync(string status, string category, string userId, int skip, int limit) { var filter = Builders.Filter.Empty; if (status != "all") filter &= Builders.Filter.Eq(value => value.Status, status); if (category.Length > 0) filter &= Builders.Filter.Eq(value => value.Category, category); if (userId.Length > 0) filter &= Builders.Filter.Eq(value => value.UserId, userId); var total = await _feedback.CountDocumentsAsync(filter); var items = await _feedback.Find(filter).SortByDescending(value => value.CreatedUtc).Skip(skip).Limit(limit).ToListAsync(); return new AppFeedbackListResponse { Items = items, Total = total, Skip = skip, Limit = limit }; } public async Task CloseAsync(string id, string status, string reviewer, string note) { if (!ObjectId.TryParse(id, out _)) return null; var now = DateTime.UtcNow; return await _feedback.FindOneAndUpdateAsync( value => value.Id == id && value.Status == QuestionReportStatus.Open, Builders.Update.Set(value => value.Status, status).Set(value => value.ReviewerNote, note) .Set(value => value.ReviewedByUserId, reviewer).Set(value => value.ReviewedUtc, now).Set(value => value.UpdatedUtc, now), new FindOneAndUpdateOptions { ReturnDocument = ReturnDocument.After }); } }