using Aberwyn.Data;
using Aberwyn.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace Aberwyn.Controllers
{
    [Authorize(Roles = "Budget")]
    [ApiController]
    [Route("api/budget")]
    public class BudgetApiController : ControllerBase
    {
        private readonly ApplicationDbContext _context;

        public BudgetApiController(ApplicationDbContext context)
        {
            _context = context;
        }


        [HttpGet("{year:int}/{month:int}")]
        public async Task<IActionResult> GetBudget(int year, int month)
        {
            try
            {

                var period = await _context.BudgetPeriods
                    .Include(p => p.Categories)
                        .ThenInclude(c => c.Items)
                    .FirstOrDefaultAsync(p => p.Year == year && p.Month == month);

                if (period == null)
                {
                    return Ok(new BudgetDto
                    {
                        Year = year,
                        Month = month,
                        Categories = new List<BudgetCategoryDto>()
                    });
                }


                var dto = new BudgetDto
                {
                    Id = period.Id,
                    Year = period.Year ?? 0,
                    Month = period.Month ?? 0,
                    Categories = period.Categories
                    .OrderBy(cat => cat.Order)
                    .Select(cat => new BudgetCategoryDto
                    {
                        Id = cat.Id,
                        Name = cat.Name,
                        Color = cat.Color,
                        Items = cat.Items
                        .OrderBy(i => i.Order) // ← sortera innan mappning
                        .Select(i => new BudgetItemDto
                        {
                            Id = i.Id,
                            Name = i.Name,
                            Amount = i.Amount,
                            IsExpense = i.IsExpense,
                            IncludeInSummary = i.IncludeInSummary,
                            BudgetItemDefinitionId = i.BudgetItemDefinitionId,
                            PaymentStatus = i.PaymentStatus
                        }).ToList()
                    }).ToList()
                };

                return Ok(dto);
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"Fel: {ex.Message} \n{ex.StackTrace}");
            }
        }

        [HttpGet("byname/{name}")]
        public async Task<IActionResult> GetBudgetByName(string name)
        {
            var period = _context.BudgetPeriods
                .Include(p => p.Categories)
                    .ThenInclude(c => c.Items)
                .AsEnumerable() // hämta från db och gör resten i minnet
                .FirstOrDefault(p => p.Name != null &&
                                     p.Name.Equals(name, StringComparison.OrdinalIgnoreCase));


            if (period == null)
            {
                return Ok(new BudgetDto
                {
                    Name = name,
                    Categories = new List<BudgetCategoryDto>()
                });
            }

            var dto = new BudgetDto
            {
                Id = period.Id,
                Name = period.Name,
                Year = period.Year ?? 0,
                Month = period.Month ?? 0,
                Categories = period.Categories
                    .OrderBy(cat => cat.Order)
                    .Select(cat => new BudgetCategoryDto
                    {
                        Id = cat.Id,
                        Name = cat.Name,
                        Color = cat.Color,
                        Items = cat.Items
                            .OrderBy(i => i.Order)
                            .Select(i => new BudgetItemDto
                            {
                                Id = i.Id,
                                Name = i.Name,
                                Amount = i.Amount,
                                IsExpense = i.IsExpense,
                                IncludeInSummary = i.IncludeInSummary,
                                BudgetItemDefinitionId = i.BudgetItemDefinitionId,
                                PaymentStatus = i.PaymentStatus
                            }).ToList()
                    }).ToList()
            };

            return Ok(dto);
        }



        [HttpPut("updatePaymentStatus")]
        public IActionResult UpdatePaymentStatus([FromBody] PaymentStatusUpdateDto dto)
        {
            if (dto == null)
                return BadRequest("dto is null");

            var item = _context.BudgetItems.Find(dto.ItemId);
            if (item == null) return NotFound();

            item.PaymentStatus = (PaymentStatus)dto.Status;
            _context.SaveChanges();

            return Ok();
        }


        [HttpPut("category/{id}")]
        public async Task<IActionResult> UpdateCategory(int id, [FromBody] BudgetCategoryDto updatedCategory)
        {
            var category = await _context.BudgetCategories
                .Include(c => c.Items)
                .FirstOrDefaultAsync(c => c.Id == id);

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

            // Hämta eller skapa kategori-definition
            if (updatedCategory.BudgetCategoryDefinitionId.HasValue)
            {
                var def = await _context.BudgetCategoryDefinitions
                    .FirstOrDefaultAsync(d => d.Id == updatedCategory.BudgetCategoryDefinitionId.Value);
                if (def != null)
                {
                    category.BudgetCategoryDefinitionId = def.Id;
                }
            }
            else
            {
                // Om ingen ID angavs, försök hitta via namn
                var def = await _context.BudgetCategoryDefinitions
                    .FirstOrDefaultAsync(d => d.Name.ToLower() == updatedCategory.Name.ToLower());

                if (def == null)
                {
                    def = new BudgetCategoryDefinition
                    {
                        Name = updatedCategory.Name,
                        Color = updatedCategory.Color ?? "#666666"
                    };
                    _context.BudgetCategoryDefinitions.Add(def);
                    await _context.SaveChangesAsync();
                }

                category.BudgetCategoryDefinitionId = def.Id;
            }

            // ✅ Uppdatera namn och färg (kan avvika från definitionens namn)
            category.Name = updatedCategory.Name;
            category.Color = updatedCategory.Color;

            // Spara undan inkommande IDs (ignorera nya med Id = 0)
            var incomingItemIds = updatedCategory.Items
                .Where(i => i.Id != 0)
                .Select(i => i.Id)
                .ToList();

            // Ta bort poster som inte längre finns i inkommande data
            var itemsToRemove = category.Items
                .Where(i => !incomingItemIds.Contains(i.Id))
                .ToList();

            _context.BudgetItems.RemoveRange(itemsToRemove);

            // Lägg till nya poster eller uppdatera befintliga
            foreach (var incoming in updatedCategory.Items)
            {
                if (incoming.Id == 0)
                {
                    category.Items.Add(new BudgetItem
                    {
                        Name = incoming.Name,
                        Amount = incoming.Amount,
                        IsExpense = incoming.IsExpense,
                        IncludeInSummary = incoming.IncludeInSummary,
                        Order = incoming.Order,
                        BudgetCategoryId = category.Id
                    });
                }
                else
                {
                    var existing = category.Items.FirstOrDefault(i => i.Id == incoming.Id);
                    if (existing != null)
                    {
                        existing.Name = incoming.Name;
                        existing.Amount = incoming.Amount;
                        existing.IsExpense = incoming.IsExpense;
                        existing.IncludeInSummary = incoming.IncludeInSummary;
                        existing.Order = incoming.Order;
                    }
                }
            }

            await _context.SaveChangesAsync();
            return NoContent();
        }

        [HttpPut("category/order")]
        public async Task<IActionResult> UpdateCategoryOrder([FromBody] List<BudgetCategoryDto> orderedCategories)
        {
            foreach (var dto in orderedCategories)
            {
                var cat = await _context.BudgetCategories.FindAsync(dto.Id);
                if (cat != null)
                    cat.Order = dto.Order;
            }

            await _context.SaveChangesAsync();
            return NoContent();
        }



        [HttpPost]
        public async Task<IActionResult> CreatePeriod([FromBody] BudgetPeriod newPeriod)
        {
            if (!string.IsNullOrWhiteSpace(newPeriod.Name))
            {
                var existingNamed = await _context.BudgetPeriods
                    .FirstOrDefaultAsync(p => p.Name != null && p.Name.ToLower() == newPeriod.Name.ToLower());

                if (existingNamed != null)
                    return Conflict("En budget med detta namn finns redan.");

                _context.BudgetPeriods.Add(newPeriod);
                await _context.SaveChangesAsync();
                return Ok(new { id = newPeriod.Id });
            }

            if (newPeriod.Year.HasValue && newPeriod.Month.HasValue)
            {
                var existing = await _context.BudgetPeriods
                    .FirstOrDefaultAsync(p => p.Year == newPeriod.Year && p.Month == newPeriod.Month);

                if (existing != null)
                    return Conflict("En budget för denna månad finns redan.");

                _context.BudgetPeriods.Add(newPeriod);
                await _context.SaveChangesAsync();
                return Ok(new { id = newPeriod.Id });
            }

            return BadRequest("Varken namn eller år/månad angivet.");
        }



        [HttpPut("item/{id}")]
        public async Task<IActionResult> UpdateItem(int id, [FromBody] BudgetItem updatedItem)
        {
            var item = await _context.BudgetItems.FindAsync(id);
            if (item == null) return NotFound();

            item.Name = updatedItem.Name;
            item.Amount = updatedItem.Amount;
            item.IsExpense = updatedItem.IsExpense;
            item.IncludeInSummary = updatedItem.IncludeInSummary;
            item.Order = updatedItem.Order;
            item.BudgetCategoryId = updatedItem.BudgetCategoryId;

            await _context.SaveChangesAsync();
            return Ok();
        }
        [HttpGet("definitions/items")]
        public async Task<IActionResult> GetItemDefinitions()
        {
            var definitions = await _context.BudgetItemDefinitions
                .OrderBy(d => d.Name)
                .ToListAsync();

            return Ok(definitions);
        }

        [HttpGet("definitions/categories")]
        public async Task<IActionResult> GetCategoryDefinitions()
        {
            var definitions = await _context.BudgetCategoryDefinitions
                .OrderBy(d => d.Name)
                .ToListAsync();

            return Ok(definitions);
        }


        [HttpPost("item")]
        public async Task<IActionResult> CreateItem([FromBody] BudgetItem newItem)
        {
            if (newItem == null || newItem.BudgetCategoryId == 0 || string.IsNullOrWhiteSpace(newItem.Name))
                return BadRequest("Ogiltig data.");

            // ✅ Om BudgetItemDefinitionId är angiven, använd den
            if (newItem.BudgetItemDefinitionId.HasValue && newItem.BudgetItemDefinitionId.Value > 0)
            {
                var existingDef = await _context.BudgetItemDefinitions
                    .FirstOrDefaultAsync(d => d.Id == newItem.BudgetItemDefinitionId);

                if (existingDef == null)
                    return BadRequest("Ogiltigt definition-ID.");

                // valfritt: du kan här också jämföra `newItem.Name != existingDef.Name`
                // och t.ex. logga det som ett användarval av etikett.
            }
            else
            {
                // Om ID inte är angivet, sök på namn som fallback
                var definition = await _context.BudgetItemDefinitions
                    .FirstOrDefaultAsync(d => d.Name.ToLower() == newItem.Name.ToLower());

                if (definition == null)
                {
                    definition = new BudgetItemDefinition
                    {
                        Name = newItem.Name,
                        IsExpense = newItem.IsExpense,
                        IncludeInSummary = newItem.IncludeInSummary
                    };
                    _context.BudgetItemDefinitions.Add(definition);
                    await _context.SaveChangesAsync();
                }

                newItem.BudgetItemDefinitionId = definition.Id;
            }

            _context.BudgetItems.Add(newItem);
            await _context.SaveChangesAsync();

            return Ok(new { id = newItem.Id });
        }

        [HttpGet("list")]
        public async Task<IActionResult> GetAllBudgets()
        {
            var periods = await _context.BudgetPeriods
                .Include(p => p.Categories)
                    .ThenInclude(c => c.Items)
                .OrderByDescending(p => p.Year)
                .ThenByDescending(p => p.Month)
                .ToListAsync();

            var result = periods.Select(p => new
            {
                id = p.Id,
                name = p.Name,
                year = p.Year,
                month = p.Month,
                categories = p.Categories
                    .OrderBy(c => c.Order)
                    .Select(c => new
                    {
                        id = c.Id,
                        name = c.Name,
                        color = c.Color,
                        total = c.Items.Sum(i => i.Amount),
                        items = c.Items
                            .OrderBy(i => i.Order)
                            .Select(i => new
                            {
                                id = i.Id,
                                name = i.Name,
                                amount = i.Amount,
                                isExpense = i.IsExpense,
                                includeInSummary = i.IncludeInSummary
                            }).ToList()
                    }).ToList(),
                total = p.Categories.Sum(c => c.Items.Sum(i => i.Amount))
            });

            return Ok(result);
        }


        // DELETE: api/budget/byname/{name}
        [HttpDelete("byname/{name}")]
        public async Task<IActionResult> DeleteByName(string name)
        {
            var period = await _context.BudgetPeriods
                .Include(p => p.Categories)
                    .ThenInclude(c => c.Items)
                .FirstOrDefaultAsync(p => p.Name != null && p.Name.ToLower() == name.ToLower());

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

            foreach (var category in period.Categories)
            {
                _context.BudgetItems.RemoveRange(category.Items);
            }

            _context.BudgetCategories.RemoveRange(period.Categories);
            _context.BudgetPeriods.Remove(period);

            await _context.SaveChangesAsync();
            return NoContent();
        }




        [HttpDelete("item/{id}")]
        public async Task<IActionResult> DeleteItem(int id)
        {
            var item = await _context.BudgetItems.FindAsync(id);
            if (item == null) return NotFound();

            _context.BudgetItems.Remove(item);
            await _context.SaveChangesAsync();
            return NoContent();
        }
        [HttpDelete("{year:int}/{month:int}")]
        public async Task<IActionResult> DeleteMonth(int year, int month)
        {
            var period = await _context.BudgetPeriods
                .Include(p => p.Categories)
                .ThenInclude(c => c.Items)
                .FirstOrDefaultAsync(p => p.Year == year && p.Month == month);

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

            // Ta bort alla items → kategorier → period
            foreach (var category in period.Categories)
            {
                _context.BudgetItems.RemoveRange(category.Items);
            }

            _context.BudgetCategories.RemoveRange(period.Categories);
            _context.BudgetPeriods.Remove(period);

            await _context.SaveChangesAsync();
            return NoContent();
        }


        [HttpPost("category")]
        public async Task<IActionResult> CreateCategory([FromBody] BudgetCategoryDto newCategoryDto)
        {
            if (newCategoryDto == null || string.IsNullOrWhiteSpace(newCategoryDto.Name))
                return BadRequest("Ogiltig data.");

            var period = await _context.BudgetPeriods
                .FirstOrDefaultAsync(p => p.Id == newCategoryDto.BudgetPeriodId);

            if (period == null)
                return NotFound("Kunde inte hitta angiven budgetperiod.");

            // 🔁 fortsätt som tidigare…
            var definition = await _context.BudgetCategoryDefinitions
                .FirstOrDefaultAsync(d => d.Name.ToLower() == newCategoryDto.Name.ToLower());

            if (definition == null)
            {
                definition = new BudgetCategoryDefinition
                {
                    Name = newCategoryDto.Name,
                    Color = newCategoryDto.Color ?? "#666666"
                };
                _context.BudgetCategoryDefinitions.Add(definition);
                await _context.SaveChangesAsync();
            }

            var category = new BudgetCategory
            {
                Name = newCategoryDto.Name,
                Color = newCategoryDto.Color ?? definition.Color,
                BudgetPeriodId = period.Id,
                Order = newCategoryDto.Order,
                BudgetCategoryDefinitionId = definition.Id
            };

            _context.BudgetCategories.Add(category);
            await _context.SaveChangesAsync();

            return Ok(new { id = category.Id });
        }



        [HttpDelete("category/{id}")]
        public async Task<IActionResult> DeleteCategory(int id)
        {
            var category = await _context.BudgetCategories
                .Include(c => c.Items)
                .FirstOrDefaultAsync(c => c.Id == id);

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

            _context.BudgetItems.RemoveRange(category.Items);
            _context.BudgetCategories.Remove(category);

            await _context.SaveChangesAsync();

            return NoContent();
        }

        /*[HttpPost("copy/{year:int}/{month:int}")]
        public async Task<IActionResult> CopyFromPreviousMonth(int year, int month)
        {
            var targetPeriod = await _context.BudgetPeriods
                .Include(p => p.Categories)
                .ThenInclude(c => c.Items)
                .FirstOrDefaultAsync(p => p.Year == year && p.Month == month);

            if (targetPeriod != null && targetPeriod.Categories.Any())
                return BadRequest("Det finns redan data för denna månad.");

            var previous = new DateTime(year, month, 1).AddMonths(-1);
            var previousPeriod = await _context.BudgetPeriods
                .Include(p => p.Categories)
                .ThenInclude(c => c.Items)
                .FirstOrDefaultAsync(p => p.Year == previous.Year && p.Month == previous.Month);

            if (previousPeriod == null)
                return NotFound("Ingen data att kopiera från.");

            var newPeriod = new BudgetPeriod
            {
                Year = year,
                Month = month,
                Categories = previousPeriod.Categories.Select(cat => new BudgetCategory
                {
                    Name = cat.Name,
                    Color = cat.Color,
                    Order = cat.Order,
                    BudgetCategoryDefinitionId = cat.BudgetCategoryDefinitionId, // 🟢 Lägg till denna rad
                    Items = cat.Items.Select(item => new BudgetItem
                    {
                        Name = item.Name,
                        Amount = item.Amount,
                        IsExpense = item.IsExpense,
                        IncludeInSummary = item.IncludeInSummary,
                        Order = item.Order,
                        BudgetItemDefinitionId = item.BudgetItemDefinitionId // 🟢 Lägg till denna rad
                    }).ToList()
                }).ToList()
            };

            _context.BudgetPeriods.Add(newPeriod);
            await _context.SaveChangesAsync();

            return Ok();
        }*/




        // Gemensam intern metod
        private async Task<BudgetPeriod?> CopyBudgetAsync(
            BudgetPeriod targetPeriod,
            BudgetPeriod sourcePeriod)
        {
            if (sourcePeriod == null) return null;

            targetPeriod.Categories = sourcePeriod.Categories.Select(cat => new BudgetCategory
            {
                Name = cat.Name,
                Color = cat.Color,
                Order = cat.Order,
                BudgetCategoryDefinitionId = cat.BudgetCategoryDefinitionId,
                Items = cat.Items.Select(item => new BudgetItem
                {
                    Name = item.Name,
                    Amount = item.Amount,
                    IsExpense = item.IsExpense,
                    IncludeInSummary = item.IncludeInSummary,
                    Order = item.Order,
                    BudgetItemDefinitionId = item.BudgetItemDefinitionId
                }).ToList()
            }).ToList();

            await _context.SaveChangesAsync();
            return targetPeriod;
        }
        [HttpPost("copy/byname/{targetName}")]
        public async Task<IActionResult> CopyToNamedBudget(
string targetName,
[FromQuery] string? from,
[FromQuery] int? fromYear,
[FromQuery] int? fromMonth)
        {
            var targetPeriod = await _context.BudgetPeriods
                .Include(p => p.Categories)
                .ThenInclude(c => c.Items)
                .FirstOrDefaultAsync(p => p.Name != null && p.Name.ToLower() == targetName.ToLower());

            if (targetPeriod == null)
            {
                targetPeriod = new BudgetPeriod { Name = targetName };
                _context.BudgetPeriods.Add(targetPeriod);
            }
            else if (targetPeriod.Categories.Any())
            {
                return BadRequest("Det finns redan data för denna budget.");
            }

            // Hämta källperiod
            var sourcePeriod = await FindSourcePeriod(from, fromYear, fromMonth);
            if (sourcePeriod == null)
                return NotFound("Ingen budget hittades att kopiera från.");

            await CopyBudgetAsync(targetPeriod, sourcePeriod);
            return Ok(new { id = targetPeriod.Id });
        }
        [HttpPost("copy/{year:int}/{month:int}")]
        public async Task<IActionResult> CopyToYearMonth(
    int year,
    int month,
    [FromQuery] string? from,
    [FromQuery] int? fromYear,
    [FromQuery] int? fromMonth)
        {
            var targetPeriod = await _context.BudgetPeriods
                .Include(p => p.Categories)
                .ThenInclude(c => c.Items)
                .FirstOrDefaultAsync(p => p.Year == year && p.Month == month);

            if (targetPeriod == null)
            {
                targetPeriod = new BudgetPeriod { Year = year, Month = month };
                _context.BudgetPeriods.Add(targetPeriod);
            }
            else if (targetPeriod.Categories.Any())
            {
                return BadRequest("Det finns redan data för denna månad.");
            }

            // Hämta källperiod
            var sourcePeriod = await FindSourcePeriod(from, fromYear, fromMonth, year, month);
            if (sourcePeriod == null)
                return NotFound("Ingen data att kopiera från.");

            await CopyBudgetAsync(targetPeriod, sourcePeriod);
            return Ok(new { id = targetPeriod.Id });
        }
    private async Task<BudgetPeriod?> FindSourcePeriod(
    string? from,
    int? fromYear,
    int? fromMonth,
    int? defaultYear = null,
    int? defaultMonth = null)
        {
            BudgetPeriod? sourcePeriod = null;

            if (!string.IsNullOrEmpty(from))
            {
                sourcePeriod = await _context.BudgetPeriods
                    .Include(p => p.Categories)
                    .ThenInclude(c => c.Items)
                    .FirstOrDefaultAsync(p => p.Name != null && p.Name.ToLower() == from.ToLower());
            }
            else if (fromYear.HasValue && fromMonth.HasValue)
            {
                sourcePeriod = await _context.BudgetPeriods
                    .Include(p => p.Categories)
                    .ThenInclude(c => c.Items)
                    .FirstOrDefaultAsync(p => p.Year == fromYear && p.Month == fromMonth);
            }
            else if (defaultYear.HasValue && defaultMonth.HasValue)
            {
                var previous = new DateTime(defaultYear.Value, defaultMonth.Value, 1).AddMonths(-1);
                sourcePeriod = await _context.BudgetPeriods
                    .Include(p => p.Categories)
                    .ThenInclude(c => c.Items)
                    .FirstOrDefaultAsync(p => p.Year == previous.Year && p.Month == previous.Month);
            }

            return sourcePeriod;
        }

        [HttpGet("metadata")]
        public async Task<IActionResult> GetMetadata([FromQuery] int? year, [FromQuery] int? month)
        {
            var categoriesQuery = _context.BudgetCategories
                .Include(c => c.BudgetPeriod)
                .Include(c => c.Items)
                    .ThenInclude(i => i.BudgetItemDefinition)
                .AsQueryable();

            if (year.HasValue)
                categoriesQuery = categoriesQuery.Where(c => c.BudgetPeriod.Year == year.Value);
            if (month.HasValue)
                categoriesQuery = categoriesQuery.Where(c => c.BudgetPeriod.Month == month.Value);

            var categories = await categoriesQuery.ToListAsync();

            var categoryDefs = categories
                .Where(c => c.BudgetCategoryDefinitionId.HasValue)
                .GroupBy(c => c.Definition?.Name ?? c.Name)
                .Select(g => new {
                    Name = g.Key,
                    Color = g.First().Color ?? "#cccccc" // direkt från kategorin
                })
                .ToList();

            var categoryLabels = categories
                .GroupBy(c => c.Name)
                .Select(g => new {
                    Name = g.Key,
                    Color = g.First().Color ?? "#cccccc"
                })
                .ToList();


            var itemDefs = categories
                .SelectMany(c => c.Items)
                .Select(i => i.BudgetItemDefinition?.Name ?? i.Name)
                .Distinct()
                .OrderBy(n => n)
                .ToList();

            var itemLabels = categories
                .SelectMany(c => c.Items)
                .Select(i => i.Name)
                .Distinct()
                .OrderBy(n => n)
                .ToList();

            Console.WriteLine($"Metadata: {categories.Count} categories, {itemLabels.Count} items");

            return Ok(new
            {
                CategoryDefinitions = categoryDefs,
                CategoryLabels = categoryLabels,
                ItemDefinitions = itemDefs,
                ItemLabels = itemLabels
            });
        }


        [HttpGet("report/spreadsheet")]
        public async Task<IActionResult> GetBudgetReport(
            [FromQuery] int? year = null,
            [FromQuery] List<int>? itemDefinitionIds = null,
            [FromQuery] List<int>? categoryDefinitionIds = null,
            [FromQuery] string? itemLabel = null,
            [FromQuery] string? categoryLabel = null,
            [FromQuery] bool includeCategoryDefinitions = false,
            [FromQuery] bool includeCategoryLabels = false,
            [FromQuery] bool includeItemDefinitions = true,
            [FromQuery] bool includeItemLabels = false)
        {
            try
            {
                // ✅ Ladda navigationsproperties för definitions
                var query = _context.BudgetPeriods
                    .Include(p => p.Categories)
                        .ThenInclude(c => c.Definition) // CategoryDefinition
                    .Include(p => p.Categories)
                        .ThenInclude(c => c.Items)
                            .ThenInclude(i => i.BudgetItemDefinition) // ItemDefinition
                    .Where(p => p.Year.HasValue && p.Month.HasValue)
                    .AsQueryable();

                if (year.HasValue)
                    query = query.Where(p => p.Year == year);

                var periods = await query
                    .OrderByDescending(p => p.Year)
                    .ThenByDescending(p => p.Month)
                    .ToListAsync();

                var reportData = periods.Select(p =>
                {
                    var filteredCategories = p.Categories
                        .Where(c =>
                            (categoryDefinitionIds == null || categoryDefinitionIds.Count == 0 ||
                             (c.BudgetCategoryDefinitionId.HasValue &&
                              categoryDefinitionIds.Contains(c.BudgetCategoryDefinitionId.Value))) &&
                            (string.IsNullOrEmpty(categoryLabel) ||
                             (c.Name ?? string.Empty).Contains(categoryLabel, StringComparison.OrdinalIgnoreCase))
                        )
                        .ToList(); // Viktigt: gå över till LINQ to Objects

                    var filteredItems = filteredCategories
                        .SelectMany(c => c.Items)
                        .Where(i =>
                            i.IncludeInSummary &&
                            (itemDefinitionIds == null || itemDefinitionIds.Count == 0 ||
                             (i.BudgetItemDefinitionId.HasValue &&
                              itemDefinitionIds.Contains(i.BudgetItemDefinitionId.Value))) &&
                            (string.IsNullOrEmpty(itemLabel) ||
                             (i.Name ?? string.Empty).Contains(itemLabel, StringComparison.OrdinalIgnoreCase))
                        )
                        .ToList();

                    // 🔹 Skapa kolumner
                    var itemDefColumns = new Dictionary<string, decimal>();
                    var itemLabelColumns = new Dictionary<string, decimal>();
                    var catDefColumns = new Dictionary<string, decimal>();
                    var catLabelColumns = new Dictionary<string, decimal>();

                    if (includeItemDefinitions)
                    {
                        foreach (var g in filteredItems
                            .Where(i => i.BudgetItemDefinition != null)
                            .GroupBy(i => i.BudgetItemDefinition!.Name))
                        {
                            if (!string.IsNullOrEmpty(g.Key))
                                itemDefColumns[g.Key] = g.Sum(i => i.IsExpense ? -i.Amount : i.Amount);
                        }
                    }

                    if (includeItemLabels)
                    {
                        foreach (var g in filteredItems
                            .Where(i => !string.IsNullOrEmpty(i.Name))
                            .GroupBy(i => i.Name))
                        {
                            itemLabelColumns[g.Key] = g.Sum(i => i.IsExpense ? -i.Amount : i.Amount);
                        }
                    }

                    if (includeCategoryDefinitions)
                    {
                        foreach (var g in filteredCategories
                            .Where(c => c.Definition != null)
                            .GroupBy(c => c.Definition!.Name))
                        {
                            if (!string.IsNullOrEmpty(g.Key))
                            {
                                var total = g.SelectMany(c => c.Items)
                                             .Where(i => i.IncludeInSummary)
                                             .Sum(i => i.IsExpense ? -i.Amount : i.Amount);
                                catDefColumns[g.Key] = total;
                            }
                        }
                    }

                    if (includeCategoryLabels)
                    {
                        foreach (var g in filteredCategories
                            .Where(c => !string.IsNullOrEmpty(c.Name))
                            .GroupBy(c => c.Name))
                        {
                            var total = g.SelectMany(c => c.Items)
                                         .Where(i => i.IncludeInSummary)
                                         .Sum(i => i.IsExpense ? -i.Amount : i.Amount);
                            catLabelColumns[g.Key] = total;
                        }
                    }

                    return new
                    {
                        id = p.Id,
                        year = p.Year ?? 0,
                        month = p.Month ?? 0,
                        income = filteredItems.Where(i => !i.IsExpense).Sum(i => i.Amount),
                        expense = filteredItems.Where(i => i.IsExpense).Sum(i => i.Amount),
                        net = filteredItems.Sum(i => i.IsExpense ? -i.Amount : i.Amount),
                        itemDefinitions = itemDefColumns,
                        itemLabels = itemLabelColumns,
                        categoryDefinitions = catDefColumns,
                        categoryLabels = catLabelColumns
                    };
                });

                return Ok(reportData);
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"[GetBudgetReport] {ex}");
                return StatusCode(500, $"Ett fel uppstod i rapportgenereringen: {ex.Message}");
            }
        }




    }

}
