561 lines
18 KiB
C#
561 lines
18 KiB
C#
// Nya versionen av MenuService med Entity Framework
|
||
using Aberwyn.Models;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using SixLabors.ImageSharp;
|
||
using SixLabors.ImageSharp.Formats.Webp;
|
||
using SixLabors.ImageSharp.Processing;
|
||
using System.Globalization;
|
||
using static Aberwyn.Data.SetupService;
|
||
|
||
namespace Aberwyn.Data
|
||
{
|
||
public class MenuService
|
||
{
|
||
private readonly ApplicationDbContext _context;
|
||
|
||
// Detta är DI-konstruktorn – används som vanligt i controllers
|
||
public MenuService(ApplicationDbContext context)
|
||
{
|
||
_context = context;
|
||
}
|
||
|
||
public static MenuService CreateWithSetup(IHostEnvironment env)
|
||
{
|
||
var setup = SetupLoader.Load(env);
|
||
var connStr = SetupLoader.GetConnectionString(setup);
|
||
var builder = new DbContextOptionsBuilder<ApplicationDbContext>();
|
||
builder.UseMySql(connStr, ServerVersion.AutoDetect(connStr));
|
||
var context = new ApplicationDbContext(builder.Options);
|
||
return new MenuService(context);
|
||
}
|
||
|
||
public List<WeeklyMenuDto> GetWeeklyMenuDto(int weekNumber, int year)
|
||
{
|
||
var query = from wm in _context.WeeklyMenus
|
||
where wm.WeekNumber == weekNumber && wm.Year == year
|
||
join mDinner in _context.Meals on wm.DinnerMealId equals mDinner.Id into dinnerJoin
|
||
from mDinner in dinnerJoin.DefaultIfEmpty()
|
||
join mLunch in _context.Meals on wm.LunchMealId equals mLunch.Id into lunchJoin
|
||
from mLunch in lunchJoin.DefaultIfEmpty()
|
||
join mBreakfast in _context.Meals on wm.BreakfastMealId equals mBreakfast.Id into breakfastJoin
|
||
from mBreakfast in breakfastJoin.DefaultIfEmpty()
|
||
select new WeeklyMenuDto
|
||
{
|
||
Id = wm.Id,
|
||
DayOfWeek = wm.DayOfWeek,
|
||
WeekNumber = wm.WeekNumber,
|
||
Year = wm.Year,
|
||
BreakfastMealId = wm.BreakfastMealId,
|
||
LunchMealId = wm.LunchMealId,
|
||
DinnerMealId = wm.DinnerMealId,
|
||
BreakfastMealName = mBreakfast.Name,
|
||
LunchMealName = mLunch.Name,
|
||
DinnerMealName = mDinner.Name,
|
||
DinnerMealThumbnail = mDinner.ThumbnailData
|
||
};
|
||
|
||
return query.ToList();
|
||
}
|
||
|
||
|
||
|
||
|
||
public void UpdateWeeklyMenu(MenuViewModel model)
|
||
{
|
||
var existing = _context.WeeklyMenus
|
||
.Where(w => w.WeekNumber == model.WeekNumber && w.Year == model.Year)
|
||
.ToList();
|
||
|
||
_context.WeeklyMenus.RemoveRange(existing);
|
||
_context.WeeklyMenus.AddRange(model.WeeklyMenus);
|
||
_context.SaveChanges();
|
||
}
|
||
public int AddMeal(Meal meal)
|
||
{
|
||
SaveMeal(meal);
|
||
return meal.Id;
|
||
}
|
||
|
||
|
||
public void SaveMeal2(Meal meal)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(meal?.Name)) return;
|
||
|
||
meal.Name = meal.Name.Trim();
|
||
meal.CreatedAt = meal.CreatedAt == default ? DateTime.Now : meal.CreatedAt;
|
||
|
||
var existing = _context.Meals
|
||
.AsNoTracking()
|
||
.FirstOrDefault(m => m.Id == meal.Id);
|
||
|
||
if (existing == null)
|
||
{
|
||
// Nytt objekt – försök behålla ID:t från prod
|
||
_context.Entry(meal).State = EntityState.Added;
|
||
}
|
||
else
|
||
{
|
||
// Befintlig – uppdatera
|
||
_context.Meals.Update(meal);
|
||
}
|
||
|
||
_context.SaveChanges();
|
||
}
|
||
|
||
public void SaveMeal(Meal meal)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(meal?.Name)) return;
|
||
|
||
meal.Name = meal.Name.Trim();
|
||
meal.CreatedAt = meal.CreatedAt == default ? DateTime.Now : meal.CreatedAt;
|
||
|
||
if (meal.Id == 0)
|
||
{
|
||
// Ny måltid
|
||
_context.Meals.Add(meal);
|
||
}
|
||
else
|
||
{
|
||
// Uppdatera existerande utan tracking-krockar
|
||
var existing = _context.Meals
|
||
.Include(m => m.Ingredients)
|
||
.FirstOrDefault(m => m.Id == meal.Id);
|
||
|
||
if (existing != null)
|
||
{
|
||
_context.Entry(existing).CurrentValues.SetValues(meal);
|
||
|
||
// OBS: Ingredienser hanteras separat
|
||
}
|
||
}
|
||
|
||
_context.SaveChanges();
|
||
}
|
||
|
||
|
||
public int GenerateMissingThumbnails()
|
||
{
|
||
var updatedCount = 0;
|
||
var meals = _context.Meals
|
||
.Where(m => m.ImageData != null && m.ThumbnailData == null)
|
||
.ToList();
|
||
|
||
foreach (var meal in meals)
|
||
{
|
||
using var ms = new MemoryStream(meal.ImageData);
|
||
using var image = Image.Load(ms);
|
||
|
||
image.Mutate(x => x.Resize(new ResizeOptions
|
||
{
|
||
Mode = ResizeMode.Max,
|
||
Size = new Size(300, 300)
|
||
}));
|
||
|
||
using var outStream = new MemoryStream();
|
||
var encoder = new WebpEncoder
|
||
{
|
||
Quality = 75
|
||
};
|
||
image.Save(outStream, encoder);
|
||
|
||
meal.ThumbnailData = outStream.ToArray();
|
||
updatedCount++;
|
||
}
|
||
|
||
_context.SaveChanges();
|
||
return updatedCount;
|
||
}
|
||
public List<Meal> GetMealsSlim(bool includeThumbnail = false)
|
||
{
|
||
if (includeThumbnail)
|
||
{
|
||
return _context.Meals
|
||
.Select(m => new Meal
|
||
{
|
||
Id = m.Id,
|
||
Name = m.Name,
|
||
Description = m.Description,
|
||
ThumbnailData = m.ThumbnailData
|
||
})
|
||
.ToList();
|
||
}
|
||
else
|
||
{
|
||
return _context.Meals
|
||
.Select(m => new Meal
|
||
{
|
||
Id = m.Id,
|
||
Name = m.Name,
|
||
Description = m.Description
|
||
})
|
||
.ToList();
|
||
}
|
||
}
|
||
|
||
public List<WeeklyMenu> GetAllWeeklyMenus()
|
||
{
|
||
var menus = _context.WeeklyMenus.ToList();
|
||
|
||
var allMeals = _context.Meals.ToDictionary(m => m.Id, m => m.Name);
|
||
|
||
foreach (var wm in menus)
|
||
{
|
||
wm.BreakfastMealName = wm.BreakfastMealId.HasValue && allMeals.TryGetValue(wm.BreakfastMealId.Value, out var breakfast)
|
||
? breakfast
|
||
: null;
|
||
|
||
wm.LunchMealName = wm.LunchMealId.HasValue && allMeals.TryGetValue(wm.LunchMealId.Value, out var lunch)
|
||
? lunch
|
||
: null;
|
||
|
||
wm.DinnerMealName = wm.DinnerMealId.HasValue && allMeals.TryGetValue(wm.DinnerMealId.Value, out var dinner)
|
||
? dinner
|
||
: null;
|
||
}
|
||
|
||
return menus;
|
||
}
|
||
|
||
|
||
public List<Ingredient> GetIngredientsForMeal(int mealId)
|
||
{
|
||
return _context.Ingredients
|
||
.Where(i => i.MealId == mealId)
|
||
.ToList();
|
||
}
|
||
|
||
public void SaveIngredients(int mealId, List<Ingredient> ingredients)
|
||
{
|
||
var existing = _context.Ingredients.Where(i => i.MealId == mealId);
|
||
_context.Ingredients.RemoveRange(existing);
|
||
|
||
foreach (var ing in ingredients)
|
||
{
|
||
ing.MealId = mealId;
|
||
}
|
||
|
||
_context.Ingredients.AddRange(ingredients);
|
||
_context.SaveChanges();
|
||
}
|
||
|
||
|
||
public List<Meal> GetMeals()
|
||
{
|
||
return _context.Meals.ToList();
|
||
}
|
||
|
||
public List<Meal> GetMealsDetailed()
|
||
{
|
||
return _context.Meals
|
||
.Include(m => m.Ingredients) // 🧠 detta behövs!
|
||
.OrderByDescending(m => m.CreatedAt)
|
||
.ToList();
|
||
}
|
||
|
||
|
||
public Meal GetMealById(int id)
|
||
{
|
||
var meal = _context.Meals
|
||
.Include(m => m.Ingredients)
|
||
.FirstOrDefault(m => m.Id == id);
|
||
return meal;
|
||
}
|
||
|
||
public void DeleteMeal(int id)
|
||
{
|
||
var meal = _context.Meals.Find(id);
|
||
if (meal != null)
|
||
{
|
||
_context.Meals.Remove(meal);
|
||
_context.SaveChanges();
|
||
}
|
||
}
|
||
|
||
public void SaveOrUpdateMeal(Meal meal)
|
||
{
|
||
SaveMeal(meal);
|
||
}
|
||
|
||
public void SaveOrUpdateMealWithIngredients(Meal meal)
|
||
{
|
||
var isNew = meal.Id == 0;
|
||
|
||
SaveMeal(meal);
|
||
|
||
if (meal.Ingredients != null && meal.Ingredients.Count > 0)
|
||
{
|
||
SaveIngredients(meal.Id, meal.Ingredients);
|
||
}
|
||
}
|
||
|
||
|
||
public List<Meal> GetMealsByCategory(string category)
|
||
{
|
||
return _context.Meals
|
||
//.Where(m => m.Category == category)
|
||
.Include(m => m.Ingredients)
|
||
.OrderBy(m => m.Name)
|
||
.ToList();
|
||
}
|
||
public List<WeeklyMenu> GetWeeklyMenu(int weekNumber, int year)
|
||
{
|
||
var menus = _context.WeeklyMenus
|
||
.Where(m => m.WeekNumber == weekNumber && m.Year == year)
|
||
.ToList();
|
||
|
||
var mealIds = menus
|
||
.SelectMany(w => new int?[] { w.BreakfastMealId, w.LunchMealId, w.DinnerMealId })
|
||
.Where(id => id.HasValue)
|
||
.Select(id => id.Value)
|
||
.Distinct()
|
||
.ToList();
|
||
|
||
var allMeals = _context.Meals
|
||
.Where(m => mealIds.Contains(m.Id))
|
||
.Select(m => new {
|
||
m.Id,
|
||
m.Name,
|
||
m.ThumbnailData // Vi tar med detta även om det bara används för middag
|
||
})
|
||
.ToList()
|
||
.ToDictionary(m => m.Id, m => m);
|
||
|
||
|
||
foreach (var wm in menus)
|
||
{
|
||
if (wm.BreakfastMealId.HasValue && allMeals.TryGetValue(wm.BreakfastMealId.Value, out var breakfast))
|
||
wm.BreakfastMealName = breakfast.Name;
|
||
|
||
if (wm.LunchMealId.HasValue && allMeals.TryGetValue(wm.LunchMealId.Value, out var lunch))
|
||
wm.LunchMealName = lunch.Name;
|
||
|
||
if (wm.DinnerMealId.HasValue && allMeals.TryGetValue(wm.DinnerMealId.Value, out var dinner))
|
||
{
|
||
wm.DinnerMealName = dinner.Name;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
return menus;
|
||
}
|
||
public WeeklyMenu? GetMenuForDate(DateTime date)
|
||
{
|
||
int week = ISOWeek.GetWeekOfYear(date);
|
||
int year = date.Year;
|
||
|
||
int dayOfWeek = (int)date.DayOfWeek;
|
||
if (dayOfWeek == 0) dayOfWeek = 7;
|
||
|
||
var menu = _context.WeeklyMenus
|
||
.FirstOrDefault(w => w.WeekNumber == week && w.Year == year && w.DayOfWeek == dayOfWeek);
|
||
|
||
if (menu != null)
|
||
{
|
||
var mealIds = new[] { menu.BreakfastMealId, menu.LunchMealId, menu.DinnerMealId }
|
||
.Where(id => id.HasValue)
|
||
.Select(id => id.Value)
|
||
.Distinct()
|
||
.ToList();
|
||
|
||
var allMeals = _context.Meals
|
||
.Where(m => mealIds.Contains(m.Id))
|
||
.ToDictionary(m => m.Id);
|
||
|
||
if (menu.BreakfastMealId is int bId && allMeals.TryGetValue(bId, out var breakfast))
|
||
{
|
||
menu.BreakfastMealName = breakfast.Name;
|
||
menu.BreakfastThumbnail = breakfast.ThumbnailData;
|
||
}
|
||
|
||
if (menu.LunchMealId is int lId && allMeals.TryGetValue(lId, out var lunch))
|
||
{
|
||
menu.LunchMealName = lunch.Name;
|
||
menu.LunchThumbnail = lunch.ThumbnailData;
|
||
}
|
||
|
||
if (menu.DinnerMealId is int dId && allMeals.TryGetValue(dId, out var dinner))
|
||
{
|
||
menu.DinnerMealName = dinner.Name;
|
||
menu.DinnerThumbnail = dinner.ThumbnailData;
|
||
}
|
||
}
|
||
|
||
return menu;
|
||
}
|
||
public List<Meal> GetMealsByCategoryName(string categoryName, string? searchTerm = null, bool onlyAvailable = false)
|
||
{
|
||
var query = _context.Meals
|
||
.Include(m => m.Category)
|
||
.Include(m => m.Ingredients)
|
||
.Where(m => m.Category != null && m.Category.Name == categoryName);
|
||
|
||
if (onlyAvailable)
|
||
query = query.Where(m => m.IsAvailable);
|
||
|
||
if (!string.IsNullOrWhiteSpace(searchTerm))
|
||
{
|
||
string lowered = searchTerm.Trim().ToLower();
|
||
query = query.Where(m => m.Name.ToLower().Contains(lowered));
|
||
}
|
||
|
||
return query
|
||
.OrderBy(m => m.Name)
|
||
.ToList();
|
||
}
|
||
|
||
|
||
public List<WeeklyMenu> GetMenuEntriesByDateRange(DateTime startDate, DateTime endDate)
|
||
{
|
||
var results = new List<WeeklyMenu>();
|
||
int startWeek = ISOWeek.GetWeekOfYear(startDate);
|
||
int endWeek = ISOWeek.GetWeekOfYear(endDate);
|
||
int startYear = startDate.Year;
|
||
int endYear = endDate.Year;
|
||
|
||
for (int y = startYear; y <= endYear; y++)
|
||
{
|
||
int fromWeek = y == startYear ? startWeek : 1;
|
||
int toWeek = y == endYear ? endWeek : ISOWeek.GetWeeksInYear(y);
|
||
|
||
for (int w = fromWeek; w <= toWeek; w++)
|
||
{
|
||
var menus = GetWeeklyMenu(w, y);
|
||
foreach (var menu in menus)
|
||
{
|
||
var dow = (DayOfWeek)(menu.DayOfWeek % 7);
|
||
var date = ISOWeek.ToDateTime(menu.Year, menu.WeekNumber, dow);
|
||
if (date.Date >= startDate.Date && date.Date <= endDate.Date)
|
||
{
|
||
menu.CreatedAt = date;
|
||
results.Add(menu);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return results;
|
||
}
|
||
public List<MealCategory> GetMealCategories()
|
||
{
|
||
return _context.MealCategories.OrderBy(c => c.DisplayOrder).ToList();
|
||
}
|
||
public int GetMealCountForCategory(int categoryId)
|
||
{
|
||
return _context.Meals.Count(m => m.MealCategoryId == categoryId);
|
||
}
|
||
|
||
public void SaveOrUpdateCategory(MealCategory cat)
|
||
{
|
||
if (cat.Id == 0)
|
||
{
|
||
_context.MealCategories.Add(cat);
|
||
}
|
||
else
|
||
{
|
||
var existing = _context.MealCategories.Find(cat.Id);
|
||
if (existing != null)
|
||
{
|
||
existing.Name = cat.Name;
|
||
existing.Slug = cat.Slug;
|
||
existing.Description = cat.Description;
|
||
existing.Icon = cat.Icon;
|
||
existing.Color = cat.Color;
|
||
existing.IsActive = cat.IsActive;
|
||
existing.DisplayOrder = cat.DisplayOrder;
|
||
}
|
||
}
|
||
_context.SaveChanges();
|
||
}
|
||
#region Lab
|
||
public void DeleteCategory(int id)
|
||
{
|
||
var cat = _context.MealCategories.Find(id);
|
||
if (cat != null)
|
||
{
|
||
_context.MealCategories.Remove(cat);
|
||
_context.SaveChanges();
|
||
}
|
||
}
|
||
public RecipeLabEntry? GetRecipeLabEntryById(int id)
|
||
{
|
||
return _context.RecipeLabEntries
|
||
.Include(e => e.Versions)
|
||
.FirstOrDefault(e => e.Id == id);
|
||
}
|
||
|
||
public void AddVersionToLabEntry(RecipeLabVersion version)
|
||
{
|
||
_context.RecipeLabVersions.Add(version);
|
||
_context.SaveChanges();
|
||
}
|
||
|
||
public void AddLabEntry(RecipeLabEntry entry)
|
||
{
|
||
_context.RecipeLabEntries.Add(entry);
|
||
_context.SaveChanges();
|
||
}
|
||
public void SaveLabVersionWithIngredients(RecipeLabVersion version, List<LabVersionIngredient> ingredients)
|
||
{
|
||
_context.RecipeLabVersions.Add(version);
|
||
_context.SaveChanges(); // så vi får ett ID
|
||
|
||
foreach (var ing in ingredients)
|
||
{
|
||
ing.RecipeLabVersionId = version.Id;
|
||
}
|
||
|
||
_context.LabVersionIngredients.AddRange(ingredients);
|
||
_context.SaveChanges();
|
||
}
|
||
// Lägg till dessa metoder i din MenuService klass
|
||
|
||
public void UpdateLabEntry(RecipeLabEntry entry)
|
||
{
|
||
var existing = _context.RecipeLabEntries.Find(entry.Id);
|
||
if (existing != null)
|
||
{
|
||
existing.Title = entry.Title;
|
||
existing.Inspiration = entry.Inspiration;
|
||
existing.Notes = entry.Notes;
|
||
existing.Tags = entry.Tags;
|
||
_context.SaveChanges();
|
||
}
|
||
}
|
||
|
||
public RecipeLabEntry GetRecipeLabEntryWithIngredients(int id)
|
||
{
|
||
return _context.RecipeLabEntries
|
||
.Include(e => e.Versions)
|
||
.Include(e => e.Ingredients)
|
||
.FirstOrDefault(e => e.Id == id);
|
||
}
|
||
public void SaveIngredientsForLabEntry(int labEntryId, List<LabIngredient> ingredients)
|
||
{
|
||
var existing = _context.LabIngredients
|
||
.Where(i => i.RecipeLabEntryId == labEntryId)
|
||
.ToList();
|
||
|
||
_context.LabIngredients.RemoveRange(existing);
|
||
|
||
foreach (var ing in ingredients)
|
||
ing.RecipeLabEntryId = labEntryId;
|
||
|
||
_context.LabIngredients.AddRange(ingredients);
|
||
_context.SaveChanges();
|
||
}
|
||
|
||
public List<RecipeLabVersion> GetLabVersionsForEntry(int entryId)
|
||
{
|
||
return _context.RecipeLabVersions
|
||
.Where(v => v.RecipeLabEntryId == entryId)
|
||
.Include(v => v.Ingredients)
|
||
.OrderByDescending(v => v.CreatedAt)
|
||
.ToList();
|
||
}
|
||
|
||
|
||
#endregion
|
||
|
||
}
|
||
}
|