using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Aberwyn.Models;
using Aberwyn.Data;
using System;
using System.Globalization;
using System.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using Aberwyn.Services;

namespace Aberwyn.Controllers
{
    public class FoodMenuController : Controller
    {
        private readonly IConfiguration _configuration;
        private readonly IHostEnvironment _env;
        private readonly MenuService _menuService;
        private readonly ApplicationDbContext _context;
        private readonly PushNotificationService _notificationService;
        private readonly PizzaNotificationService _pizzaNotifier;

        public FoodMenuController(MenuService menuService, IConfiguration configuration, IHostEnvironment env, ApplicationDbContext context, PushNotificationService notificationService, PizzaNotificationService pizzaNotificationService)
        {
            _menuService = menuService;

            _configuration = configuration;
            _env = env;
            _context = context;
            _notificationService = notificationService;
            _pizzaNotifier = pizzaNotificationService;
        }

        [HttpGet]
        public IActionResult PizzaOrder()
        {
            var meals = _menuService.GetMealsByCategoryName("Pizza", onlyAvailable: true);
            Console.WriteLine("Pizzas: ", meals);
            var dtoList = meals.Select(m => MealListDto.FromMeal(m)).ToList();
            ViewBag.Pizzas = dtoList;

            ViewBag.RestaurantIsOpen = GetRestaurantStatus();

            int? lastId = HttpContext.Session.GetInt32("LastPizzaOrderId");
            if (lastId.HasValue)
            {
                var previousOrder = _context.PizzaOrders.FirstOrDefault(o => o.Id == lastId.Value);
                if (previousOrder != null)
                {
                    ViewBag.PreviousOrder = previousOrder;
                }
            }

            return View();
        }



        [HttpGet]
        public IActionResult EditPizzaOrder(int id)
        {
            var order = _context.PizzaOrders.FirstOrDefault(o => o.Id == id);
            if (order == null)
            {
                return RedirectToAction("PizzaOrder");
            }

            // S�tt session s� vi vet att det �r en uppdatering
            HttpContext.Session.SetInt32("LastPizzaOrderId", order.Id);

            // Visa formul�ret
            TempData["ForceShowForm"] = "true";

            return RedirectToAction("PizzaOrder");
        }



        [HttpPost]
        public IActionResult ClearPizzaSession()
        {
            HttpContext.Session.Remove("LastPizzaOrderId");
            return RedirectToAction("PizzaOrder");
        }


        [HttpPost]
        public async Task<IActionResult> PizzaOrder(string customerName, string pizzaName, string ingredients, int? orderId)
        {
            if (string.IsNullOrWhiteSpace(customerName) || string.IsNullOrWhiteSpace(pizzaName))
            {
                TempData["Error"] = "Fyll i både namn och pizza!";
                return RedirectToAction("PizzaOrder");
            }

            int? lastId = orderId ?? HttpContext.Session.GetInt32("LastPizzaOrderId");
            PizzaOrder order;

            if (lastId.HasValue)
            {
                // Uppdatera befintlig order
                order = _context.PizzaOrders.FirstOrDefault(o => o.Id == lastId.Value);
                if (order != null)
                {
                    order.CustomerName = customerName.Trim();
                    order.PizzaName = pizzaName.Trim();
                    order.IngredientsJson = ingredients;
                    order.Status = "Unconfirmed";
                    _context.SaveChanges();

                    TempData["Success"] = $"Din beställning har uppdaterats!";
                    return RedirectToAction("PizzaOrder");
                }
            }

            // Annars skapa ny
            order = new PizzaOrder
            {
                CustomerName = customerName.Trim(),
                PizzaName = pizzaName.Trim(),
                IngredientsJson = ingredients,
                Status = "Unconfirmed",
                OrderedAt = DateTime.Now
            };

            _context.PizzaOrders.Add(order);
            _context.SaveChanges();
            TempData["ForceShowForm"] = "true";
            await _pizzaNotifier.NotifyPizzaSubscribersAsync(order.PizzaName, order.CustomerName);

            HttpContext.Session.SetInt32("LastPizzaOrderId", order.Id);

            TempData["Success"] = $"Tack {order.CustomerName}! Din pizza är beställd!";
            return RedirectToAction("PizzaOrder");
        }



        [Authorize(Roles = "Chef")]
        public IActionResult PizzaAdmin(DateTime? date)
        {
            var selectedDate = date ?? DateTime.Today;
            var nextDay = selectedDate.AddDays(1);

            var allOrders = _context.PizzaOrders
                .Where(o => o.OrderedAt >= selectedDate && o.OrderedAt < nextDay)
                .OrderBy(o => o.OrderedAt)
                .ToList();

            var viewModel = new PizzaAdminViewModel
            {
                ActiveOrders = allOrders.Where(o => o.Status != "Finished").ToList(),
                CompletedOrders = allOrders.Where(o => o.Status == "Finished").ToList()
            };

            var allMeals = _menuService.GetMeals();

            var categories = _menuService.GetMealCategories();
            var pizzaCategory = categories.FirstOrDefault(c => c.Name.Equals("Pizza", StringComparison.OrdinalIgnoreCase));

            viewModel.AvailablePizzas = allMeals
                .Where(m => m.MealCategoryId == pizzaCategory?.Id)
                .OrderBy(m => m.Name)
                .ToList();


            ViewBag.RestaurantIsOpen = GetRestaurantStatus();

            return View(viewModel);
        }




        [HttpPost]
        [Authorize(Roles = "Chef")]
        public async Task<IActionResult> UpdatePizzaOrder(int id, string status, string ingredientsJson)
        {
            var order = await _context.PizzaOrders.FirstOrDefaultAsync(p => p.Id == id);
            if (order == null)
                return RedirectToAction("PizzaAdmin");

            order.Status = status;
            order.IngredientsJson = ingredientsJson;
            await _context.SaveChangesAsync();

            // Skicka pushnotiser till kopplade prenumeranter
            var subscribers = await _context.PushSubscribers
                .Where(s => s.PizzaOrderId == id)
                .ToListAsync();

            var payload = $@"{{
        ""title"": ""Din pizza! 🍕"",
        ""body"": ""Statusuppdatering: {status}""
    }}";

            foreach (var sub in subscribers)
            {
                try
                {
                    _notificationService.SendNotification(sub.Endpoint, sub.P256DH, sub.Auth, payload);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"❌ Kunde inte skicka notis till {sub.Endpoint}: {ex.Message}");
                }
            }

            return RedirectToAction("PizzaAdmin");
        }


        [Authorize(Roles = "Chef")]
        public IActionResult Veckomeny(int? week, int? year)
        {
            var menuService = _menuService;

            var today = DateTime.Today;

            // Starta alltid från ett GILTIGT datum
            DateTime referenceDate;

            if (week.HasValue && year.HasValue)
            {
                // Om week < 1 eller > 53 – tolka det som navigering
                // från närliggande vecka i stället för att krascha
                int safeWeek = Math.Clamp(week.Value, 1, 53);
                referenceDate = ISOWeek.ToDateTime(year.Value, safeWeek, DayOfWeek.Monday);

                // Justera datumet med differensen (ex: week=0 → -1 vecka)
                referenceDate = referenceDate.AddDays((week.Value - safeWeek) * 7);
            }
            else
            {
                referenceDate = today;
            }

            // Normalisera alltid via datum
            int resolvedWeek = ISOWeek.GetWeekOfYear(referenceDate);
            int resolvedYear = ISOWeek.GetYear(referenceDate);

            var menus = menuService.GetWeeklyMenu(resolvedWeek, resolvedYear);

            var vm = new WeeklyMenuViewModel
            {
                WeekNumber = resolvedWeek,
                Year = resolvedYear,
                WeeklyMenus = menus,
                WishList = _context.MealWishes
                .Include(w => w.RequestedByUser)
                .Where(w => !w.IsArchived)
                .OrderByDescending(w => w.CreatedAt)
                .ToList()
            };

            var recent = menuService
                .GetMenuEntriesByDateRange(DateTime.Now.AddDays(-28), DateTime.Now)
                .Select(x => new WeeklyMenuViewModel.RecentMenuEntry
                {
                    Date = x.CreatedAt,
                    BreakfastMealName = x.BreakfastMealName,
                    LunchMealName = x.LunchMealName,
                    DinnerMealName = x.DinnerMealName
                })
                .ToList();

            vm.RecentEntries = recent;
            ViewBag.AvailableMeals = menuService.GetMeals();

            return View(vm);
        }

        [HttpPost]
        public IActionResult AddMealAjax([FromBody] Meal meal)
        {
            if (meal == null || string.IsNullOrWhiteSpace(meal.Name))
                return BadRequest("Ogiltigt m�ltidsobjekt.");

            var service = _menuService;

            // Kontrollera om en m�ltid med samma namn redan finns
            var existing = service.GetMeals()
                .FirstOrDefault(m => m.Name.Equals(meal.Name, StringComparison.OrdinalIgnoreCase));

            if (existing == null)
            {
                // Fyll i CreatedAt om det inte s�tts automatiskt i databasen
                meal.CreatedAt = DateTime.Now;
                service.SaveOrUpdateMeal(meal);
                existing = meal;
            }
            else
            {
                // Om m�ltiden finns men saknar data (t.ex. �r bara ett namn) kan vi uppdatera den
                existing.Description = meal.Description;
                existing.ProteinType = meal.ProteinType;
                existing.CarbType = meal.CarbType;
                existing.RecipeUrl = meal.RecipeUrl;
                existing.ImageUrl = meal.ImageUrl;
                service.SaveOrUpdateMeal(existing);
            }

            return Json(new
            {
                Id = existing.Id,
                Name = existing.Name,
                Description = existing.Description,
                ProteinType = existing.ProteinType,
                CarbType = existing.CarbType,
                RecipeUrl = existing.RecipeUrl
            });
        }

        public IActionResult MealAdmin()
        {
            var service = _menuService;
            var meals = service.GetMealsDetailed();
            return View("MealAdmin", meals);
        }

        [HttpGet]
        public JsonResult SearchMeals(string term)
        {
            if (string.IsNullOrWhiteSpace(term))
                return Json(new List<string>());

            var menuService = _menuService;
            var meals = menuService.GetMeals();

            var result = meals
                .Where(m => m.Name != null && m.Name.Contains(term, StringComparison.OrdinalIgnoreCase))
                .Select(m => m.Name)
                .Distinct()
                .Take(10)
                .ToList();

            return Json(result);
        }

        [HttpPost]
        public IActionResult SaveVeckomeny(IFormCollection form, int week, int year)
        {
            var menuService = _menuService;
            var allMeals = menuService.GetMeals();

            var model = new MenuViewModel
            {
                WeekNumber = week,
                Year = year,
                WeeklyMenus = new List<WeeklyMenu>()
            };

            var entriesByDay = new Dictionary<int, WeeklyMenu>();

            foreach (var key in form.Keys.Where(k => k.StartsWith("Meal[", StringComparison.OrdinalIgnoreCase)))
            {
                var match = Regex.Match(key, @"Meal\[(\d+)\]\[(\w+)\]");
                if (!match.Success) continue;

                int day = int.Parse(match.Groups[1].Value);
                string mealType = match.Groups[2].Value;
                string mealName = form[key];
                string cook = form[$"Cook[{day}]"];

                if (!entriesByDay.TryGetValue(day, out var entry))
                {
                    entry = new WeeklyMenu
                    {
                        WeekNumber = week,
                        Year = year,
                        DayOfWeek = day + 1
                    };
                    entriesByDay[day] = entry;
                }

                entry.Cook = cook;
                entry.Date = FirstDateOfISOWeek(year, week).AddDays(day);
                if (string.IsNullOrWhiteSpace(mealName))
                {
                    switch (mealType.ToLower())
                    {
                        case "lunch":
                            entry.LunchMealId = null;
                            entry.LunchMealName = null;
                            break;
                        case "middag":
                            entry.DinnerMealId = null;
                            entry.DinnerMealName = null;
                            break;
                        case "frukost":
                            entry.BreakfastMealId = null;
                            entry.BreakfastMealName = null;
                            break;
                    }
                    continue;
                }

                var meal = allMeals.FirstOrDefault(m => m.Name.Equals(mealName, StringComparison.OrdinalIgnoreCase))
                           ?? new Meal { Name = mealName };

                if (meal.Id == 0)
                    menuService.SaveOrUpdateMeal(meal);

                switch (mealType.ToLower())
                {
                    case "lunch":
                        entry.LunchMealId = meal.Id;
                        entry.LunchMealName = meal.Name;
                        break;
                    case "middag":
                        entry.DinnerMealId = meal.Id;
                        entry.DinnerMealName = meal.Name;
                        break;
                    case "frukost":
                        entry.BreakfastMealId = meal.Id;
                        entry.BreakfastMealName = meal.Name;
                        break;
                }
            }

            model.WeeklyMenus = entriesByDay.Values.ToList();
            menuService.UpdateWeeklyMenu(model);

            return RedirectToAction("Veckomeny", new { week, year });
        }
        
        private bool GetRestaurantStatus()
        {
            var value = _context.AppSettings.FirstOrDefault(s => s.Key == "RestaurantIsOpen")?.Value;
            return bool.TryParse(value, out var isOpen) && isOpen;
        }


        private void SetRestaurantStatus(bool isOpen)
        {
            var setting = _context.AppSettings.FirstOrDefault(s => s.Key == "RestaurantIsOpen");
            if (setting == null)
            {
                setting = new AppSetting { Key = "RestaurantIsOpen", Value = isOpen.ToString().ToLower() };
                _context.AppSettings.Add(setting);
            }
            else
            {
                setting.Value = isOpen.ToString().ToLower();
                _context.AppSettings.Update(setting);
            }
            _context.SaveChanges();
        }
        [HttpPost]
        [Authorize(Roles = "Chef")]
        public IActionResult ToggleRestaurant(bool isOpen)
        {
            var existing = _context.AppSettings.FirstOrDefault(s => s.Key == "RestaurantIsOpen");
            if (existing != null)
            {
                existing.Value = isOpen.ToString();
            }
            else
            {
                _context.AppSettings.Add(new AppSetting { Key = "RestaurantIsOpen", Value = isOpen.ToString() });
            }
            _context.SaveChanges();

            return RedirectToAction("PizzaAdmin");
        }
        [Authorize(Roles = "Chef")]
        public IActionResult PizzaAdminPartial()
        {
            var today = DateTime.Today;
            var tomorrow = today.AddDays(1);

            var allOrders = _context.PizzaOrders
                .Where(o => o.OrderedAt >= today && o.OrderedAt < tomorrow)
                .OrderBy(o => o.OrderedAt)
                .ToList();

            var allMeals = _menuService.GetMealsByCategory("Pizza");

            var vm = new PizzaAdminViewModel
            {
                ActiveOrders = allOrders.Where(o => o.Status != "Finished").ToList(),
                CompletedOrders = allOrders.Where(o => o.Status == "Finished").ToList(),
                AvailablePizzas = allMeals,
                RestaurantIsOpen = GetRestaurantStatus()
            };

            return PartialView("_PizzaAdminPartial", vm);
        }


        [HttpPost]
        [Authorize(Roles = "Chef")]
        public IActionResult UpdatePizzaAvailability(List<int> availableIds)
        {
            availableIds ??= new List<int>(); // Om null, ers�tt med tom lista

            var allPizzas = _menuService.GetMealsByCategory("Pizza");

            foreach (var meal in allPizzas)
            {
                var isAvailable = availableIds.Contains(meal.Id);
                if (meal.IsAvailable != isAvailable)
                {
                    meal.IsAvailable = isAvailable;
                    _menuService.SaveOrUpdateMeal(meal);
                }
            }

            return RedirectToAction("PizzaAdmin");
        }

        [Authorize(Roles = "Chef")]
        [HttpGet]
        public IActionResult Calculator()
        {
            var plans = _context.DoughPlans
                .OrderByDescending(p => p.Datum)
                .ThenByDescending(p => p.Id)
                .ToList();

            ViewBag.Plans = plans;

            return View(new DoughPlan { AntalPizzor = 8, ViktPerPizza = 220 });
        }
        [HttpGet]
        public IActionResult GetRecentMenuEntries(int weeksBack = 4)
        {
            var today = DateTime.Today;

            // Datum för måndag i nuvarande vecka
            int deltaToMonday = ((int)today.DayOfWeek + 6) % 7; // måndag=0, söndag=6
            var thisWeekMonday = today.AddDays(-deltaToMonday);

            // Startdatum: måndag X veckor bak
            var startMonday = thisWeekMonday.AddDays(-7 * weeksBack);

            // Slutdatum: söndag för förra veckan
            var endSunday = thisWeekMonday.AddDays(-1);

            // Hämta alla veckomenyer inom intervallet
            var allMenus = _context.WeeklyMenus
                .Where(w => w.Date >= startMonday && w.Date <= endSunday)
                .OrderBy(w => w.Date)
                .ToList();

            // Hämta alla relevanta meal IDs
            var mealIds = allMenus
                .SelectMany(w => new[] { w.BreakfastMealId, w.LunchMealId, w.DinnerMealId })
                .Where(id => id.HasValue)
                .Select(id => id!.Value)
                .Distinct()
                .ToList();

            var meals = _context.Meals
                .Where(m => mealIds.Contains(m.Id))
                .ToDictionary(m => m.Id, m => m.Name);

            // Skapa entries
            var entries = allMenus
                .Select(w => new RecentMenuEntry
                {
                    Date = w.Date,
                    WeekNumber = ISOWeek.GetWeekOfYear(w.Date),
                    Year = w.Date.Year,
                    BreakfastMealName = w.BreakfastMealId.HasValue && meals.ContainsKey(w.BreakfastMealId.Value)
                        ? meals[w.BreakfastMealId.Value]
                        : "—",
                    LunchMealName = w.LunchMealId.HasValue && meals.ContainsKey(w.LunchMealId.Value)
                        ? meals[w.LunchMealId.Value]
                        : "—",
                    DinnerMealName = w.DinnerMealId.HasValue && meals.ContainsKey(w.DinnerMealId.Value)
                        ? meals[w.DinnerMealId.Value]
                        : "—"
                })
                .OrderBy(e => e.Date)
                .ToList();

            return Json(entries);
        }



        private static DateTime FirstDateOfISOWeek(int year, int weekOfYear)
        {
            DateTime jan4 = new DateTime(year, 1, 4);
            int daysOffset = DayOfWeek.Thursday - jan4.DayOfWeek;

            DateTime firstThursday = jan4.AddDays(daysOffset);
            var cal = System.Globalization.CultureInfo.CurrentCulture.Calendar;
            int firstWeek = cal.GetWeekOfYear(firstThursday, System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);

            if (firstWeek <= 1)
                weekOfYear -= 1;

            DateTime result = firstThursday.AddDays(weekOfYear * 7);
            return result.AddDays(-3); // tillbaka till måndag
        }




        [Authorize(Roles = "Chef")]
        [HttpPost]
        public IActionResult SaveDoughPlan([FromBody] DoughPlan model)
        {
            if (model == null) return BadRequest();

            _context.DoughPlans.Add(model);
            _context.SaveChanges();

            return Json(new { success = true, id = model.Id });
        }

    }

}
