// 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

    }
}
