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,
                    Month = period.Month,
                    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
                        }).ToList()
                    }).ToList()
                };

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

        [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)
        {
            _context.BudgetPeriods.Add(newPeriod);
            await _context.SaveChangesAsync();
            return CreatedAtAction(nameof(GetBudget), new { year = newPeriod.Year, month = newPeriod.Month }, newPeriod);
        }

        [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 });
        }



        [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.Year == newCategoryDto.Year && p.Month == newCategoryDto.Month);

            if (period == null)
            {
                period = new BudgetPeriod
                {
                    Year = newCategoryDto.Year,
                    Month = newCategoryDto.Month
                };
                _context.BudgetPeriods.Add(period);
                await _context.SaveChangesAsync();
            }

            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();
        }



    }
}
