using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Recepie.Data;
using Recepie.Models;
using Recepie.ViewModels;

namespace Recepie.Controllers
{
    public class WeekPlannerController : Controller
    {
        private readonly RecipeContext _context;

        public WeekPlannerController(RecipeContext context)
        {
            _context = context;
        }

        public async Task<IActionResult> Index(DateTime? startDate = null)
        {
            var weekStart = startDate ?? DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek + 1); // Monday

            var currentWeekPlan = await _context.WeekPlans
                .Include(wp => wp.DayPlans.OrderBy(dp => dp.Date))
                .ThenInclude(dp => dp.Recipe)
                .FirstOrDefaultAsync(wp => wp.StartDate.Date == weekStart.Date);

            var mainIngredients = await GetMainIngredientsAsync();

            var viewModel = new WeekPlannerViewModel
            {
                CurrentWeekPlan = currentWeekPlan,
                AvailableMainIngredients = mainIngredients,
                StartDate = weekStart
            };

            return View(viewModel);
        }
        [HttpPost]
        public async Task<IActionResult> CreateWeekPlan(DateTime startDate, string planName = "")
        {
            if (string.IsNullOrEmpty(planName))
                planName = $"Week Plan {startDate:MMM dd, yyyy}";

            var weekPlan = new WeekPlan
            {
                Name = planName,
                StartDate = startDate,
                CreatedAt = DateTime.Now
            };

            _context.WeekPlans.Add(weekPlan);
            await _context.SaveChangesAsync();

            // Create day plans for the week
            for (int i = 0; i < 7; i++)
            {
                var dayPlan = new DayPlan
                {
                    WeekPlanId = weekPlan.Id,
                    DayOfWeek = (DayOfWeek)((int)(startDate.DayOfWeek + i) % 7),
                    Date = startDate.AddDays(i)
                };
                _context.DayPlans.Add(dayPlan);
            }

            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }

        public async Task<IActionResult> ConfigureDay(int weekPlanId, DayOfWeek dayOfWeek)
        {
            var weekPlan = await _context.WeekPlans
                .Include(wp => wp.DayPlans)
                .FirstOrDefaultAsync(wp => wp.Id == weekPlanId);

            if (weekPlan == null)
                return NotFound();

            var dayPlan = weekPlan.DayPlans.FirstOrDefault(dp => dp.DayOfWeek == dayOfWeek);
            if (dayPlan == null)
                return NotFound();

            var mainIngredients = await GetMainIngredientsAsync();
            var suggestedRecipes = await GetSuggestedRecipesAsync(dayPlan.MainIngredient, dayPlan.BannedIngredients, dayPlan.RequiredIngredients);

            var viewModel = new DayPlanConfigViewModel
            {
                DayPlanId = dayPlan.Id,
                DayOfWeek = dayPlan.DayOfWeek,
                Date = dayPlan.Date,
                SelectedMainIngredient = dayPlan.MainIngredient,
                BannedIngredients = dayPlan.BannedIngredients,
                RequiredIngredients = dayPlan.RequiredIngredients,
                AvailableMainIngredients = mainIngredients,
                SuggestedRecipes = suggestedRecipes,
                SelectedRecipeId = dayPlan.RecipeId
            };

            return View(viewModel);
        }

        [HttpPost]
        public async Task<IActionResult> UpdateDayPlan(DayPlanConfigViewModel model)
        {
            var dayPlan = await _context.DayPlans.FindAsync(model.DayPlanId);
            if (dayPlan == null)
                return NotFound();

            dayPlan.MainIngredient = model.SelectedMainIngredient;
            dayPlan.BannedIngredients = model.BannedIngredients;
            dayPlan.RequiredIngredients = model.RequiredIngredients;
            dayPlan.RecipeId = model.SelectedRecipeId;

            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }

        [HttpPost]
        public async Task<IActionResult> RandomizeRecipe(int dayPlanId)
        {
            var dayPlan = await _context.DayPlans.FindAsync(dayPlanId);
            if (dayPlan == null)
                return NotFound();

            // Get all recipes for this week to avoid repeats
            var weekPlan = await _context.WeekPlans
                .Include(wp => wp.DayPlans)
                .FirstOrDefaultAsync(wp => wp.DayPlans.Any(dp => dp.Id == dayPlanId));

            var usedRecipeIds = weekPlan?.DayPlans
                .Where(dp => dp.RecipeId.HasValue && dp.Id != dayPlanId)
                .Select(dp => dp.RecipeId!.Value)
                .ToList() ?? new List<int>();

            var recipes = await GetSuggestedRecipesAsync(dayPlan.MainIngredient, dayPlan.BannedIngredients, dayPlan.RequiredIngredients);

            // Filter out already used recipes this week
            var availableRecipes = recipes.Where(r => !usedRecipeIds.Contains(r.Id)).ToList();

            // If no unused recipes, fall back to all suggested recipes
            if (!availableRecipes.Any())
                availableRecipes = recipes;

            if (availableRecipes.Any())
            {
                // Use cryptographically secure random for better distribution
                using var rng = System.Security.Cryptography.RandomNumberGenerator.Create();
                var randomBytes = new byte[4];
                rng.GetBytes(randomBytes);
                var randomIndex = Math.Abs(BitConverter.ToInt32(randomBytes, 0)) % availableRecipes.Count;

                var randomRecipe = availableRecipes[randomIndex];
                dayPlan.RecipeId = randomRecipe.Id;
                await _context.SaveChangesAsync();
            }

            return RedirectToAction(nameof(Index));
        }

        private async Task<List<string>> GetMainIngredientsAsync()
        {
            // Define clean, consolidated main ingredient categories
            var mainIngredientCategories = new List<string>
            {
                "Pasta",
                "Potatis",
                "Ris",
                "Kött",
                "Kyckling",
                "Fisk",
                "Skaldjur",
                "Ägg",
                "Bönor & Linser",
                "Vegetariskt",
                "Soppa",
                "Sallad"
            };

            return mainIngredientCategories;
        }

        private async Task<List<Recipe>> GetSuggestedRecipesAsync(string? mainIngredient, string? bannedIngredients, string? requiredIngredients)
        {
            var query = _context.Recipes
                .Include(r => r.RecipeIngredients)
                .ThenInclude(ri => ri.Ingredient)
                .AsQueryable();

            // Filter by main ingredient with smart categorization
            if (!string.IsNullOrEmpty(mainIngredient))
            {
                var searchTerms = GetIngredientSearchTerms(mainIngredient);
                query = query.Where(r => r.RecipeIngredients
                    .Any(ri => ri.Ingredient != null && ri.Ingredient.Name != null &&
                        searchTerms.Any(term => ri.Ingredient.Name.ToLower().Contains(term))));
            }

            // Filter out banned ingredients
            if (!string.IsNullOrEmpty(bannedIngredients))
            {
                var banned = bannedIngredients.Split(',', StringSplitOptions.RemoveEmptyEntries)
                    .Select(b => b.Trim().ToLower()).ToList();

                query = query.Where(r => !r.RecipeIngredients
                    .Any(ri => ri.Ingredient != null && ri.Ingredient.Name != null && banned.Any(b => ri.Ingredient.Name!.ToLower().Contains(b))));
            }

            // Filter by required ingredients
            if (!string.IsNullOrEmpty(requiredIngredients))
            {
                var required = requiredIngredients.Split(',', StringSplitOptions.RemoveEmptyEntries)
                    .Select(req => req.Trim().ToLower()).ToList();

                foreach (var req in required)
                {
                    query = query.Where(r => r.RecipeIngredients
                        .Any(ri => ri.Ingredient != null && ri.Ingredient.Name != null && ri.Ingredient.Name.ToLower().Contains(req)));
                }
            }

            // Increase the pool significantly and add randomization at DB level
            return await query.OrderBy(r => Guid.NewGuid()).Take(50).ToListAsync();
        }

        private List<string> GetIngredientSearchTerms(string mainIngredient)
        {
            return mainIngredient.ToLower() switch
            {
                "pasta" => new List<string> { "pasta", "spaghetti", "penne", "fusilli", "linguine", "tagliatelle", "fettuccine", "makaroner", "lasagne", "ravioli", "gnocchi" },
                "potatis" => new List<string> { "potatis", "potato", "potatismos", "klyftpotatis", "gratäng" },
                "ris" => new List<string> { "ris", "rice", "risotto", "basmati", "jasmin" },
                "kött" => new List<string> { "kött", "nötkött", "fläsk", "lamm", "köttfärs", "bacon", "skinka", "korv" },
                "kyckling" => new List<string> { "kyckling", "chicken", "kycklingfilé", "kycklingklubb", "kycklingbröst" },
                "fisk" => new List<string> { "fisk", "lax", "torsk", "abborre", "tonfisk", "salmon", "cod" },
                "skaldjur" => new List<string> { "räkor", "krabba", "hummer", "musslor", "shrimp", "crab", "lobster" },
                "ägg" => new List<string> { "ägg", "egg", "omelett", "scrambled" },
                "bönor & linser" => new List<string> { "bönor", "linser", "kikärtor", "beans", "lentils", "chickpeas" },
                "vegetariskt" => new List<string> { "tofu", "halloumi", "quinoa", "bulgur", "tempeh", "vegetarisk" },
                "soppa" => new List<string> { "soppa", "soup", "buljong", "bisque" },
                "sallad" => new List<string> { "sallad", "salad", "coleslaw", "caesar" },
                _ => new List<string> { mainIngredient.ToLower() }
            };
        }
    }
}