using MealPlan.Api.Data;
using MealPlan.Api.DTOs.IngredientCatalog;
using MealPlan.Api.Models;
using Microsoft.EntityFrameworkCore;

namespace MealPlan.Api.Services;

public class IngredientCatalogService : IIngredientCatalogService
{
    private readonly AppDbContext _db;

    public IngredientCatalogService(AppDbContext db) => _db = db;

    public async Task<IReadOnlyList<IngredientCategoryDto>> GetCategoriesAsync(CancellationToken ct = default)
    {
        return await _db.IngredientCategories.AsNoTracking()
            .Where(c => c.IsActive)
            .OrderBy(c => c.SortOrder)
            .ThenBy(c => c.Name)
            .Select(c => new IngredientCategoryDto
            {
                Id = c.Id,
                Code = c.Code,
                Name = c.Name,
                ItemCount = c.Items.Count(i => i.IsActive),
            })
            .ToListAsync(ct);
    }

    public async Task<IReadOnlyList<IngredientNutritionItemDto>> GetItemsAsync(
        string? categoryCode,
        string? search,
        CancellationToken ct = default)
    {
        var query = _db.IngredientNutritionCatalog.AsNoTracking()
            .Include(i => i.Category)
            .Where(i => i.IsActive && i.Category!.IsActive);

        if (!string.IsNullOrWhiteSpace(categoryCode))
        {
            var code = categoryCode.Trim().ToLowerInvariant();
            query = query.Where(i => i.Category!.Code == code);
        }

        if (!string.IsNullOrWhiteSpace(search))
        {
            var term = search.Trim().ToLowerInvariant();
            query = query.Where(i =>
                i.Name.ToLower().Contains(term) ||
                (i.NamePl != null && i.NamePl.ToLower().Contains(term)));
        }

        var rows = await query
            .OrderBy(i => i.Category!.SortOrder)
            .ThenBy(i => i.SortOrder)
            .ThenBy(i => i.Name)
            .ToListAsync(ct);

        return rows.Select(MapItem).ToList();
    }

    public async Task<IngredientNutritionItemDto?> GetItemByIdAsync(int id, CancellationToken ct = default)
    {
        var row = await _db.IngredientNutritionCatalog.AsNoTracking()
            .Include(i => i.Category)
            .FirstOrDefaultAsync(i => i.Id == id && i.IsActive, ct);
        return row is null ? null : MapItem(row);
    }

    public async Task<IngredientNutritionItemDto?> CreateItemAsync(
        UpsertIngredientNutritionItemDto dto,
        CancellationToken ct = default)
    {
        var category = await _db.IngredientCategories.AsNoTracking()
            .FirstOrDefaultAsync(c => c.Id == dto.CategoryId && c.IsActive, ct);
        if (category is null) return null;

        var entity = new IngredientNutritionCatalogItem
        {
            CategoryId = dto.CategoryId,
            Name = dto.Name.Trim(),
            NamePl = string.IsNullOrWhiteSpace(dto.NamePl) ? null : dto.NamePl.Trim(),
            CaloriesPer100G = dto.CaloriesPer100G,
            ProteinGPer100G = dto.ProteinGPer100G,
            FatGPer100G = dto.FatGPer100G,
            CarbsGPer100G = dto.CarbsGPer100G,
            FiberGPer100G = dto.FiberGPer100G,
            SortOrder = dto.SortOrder,
            IsActive = dto.IsActive,
        };

        _db.IngredientNutritionCatalog.Add(entity);
        await _db.SaveChangesAsync(ct);

        entity.Category = category;
        return MapItem(entity);
    }

    public async Task<IngredientNutritionItemDto?> UpdateItemAsync(
        int id,
        UpsertIngredientNutritionItemDto dto,
        CancellationToken ct = default)
    {
        var entity = await _db.IngredientNutritionCatalog
            .Include(i => i.Category)
            .FirstOrDefaultAsync(i => i.Id == id, ct);
        if (entity is null) return null;

        var category = await _db.IngredientCategories.AsNoTracking()
            .FirstOrDefaultAsync(c => c.Id == dto.CategoryId && c.IsActive, ct);
        if (category is null) return null;

        entity.CategoryId = dto.CategoryId;
        entity.Name = dto.Name.Trim();
        entity.NamePl = string.IsNullOrWhiteSpace(dto.NamePl) ? null : dto.NamePl.Trim();
        entity.CaloriesPer100G = dto.CaloriesPer100G;
        entity.ProteinGPer100G = dto.ProteinGPer100G;
        entity.FatGPer100G = dto.FatGPer100G;
        entity.CarbsGPer100G = dto.CarbsGPer100G;
        entity.FiberGPer100G = dto.FiberGPer100G;
        entity.SortOrder = dto.SortOrder;
        entity.IsActive = dto.IsActive;

        await _db.SaveChangesAsync(ct);
        entity.Category = category;
        return MapItem(entity);
    }

    public async Task<bool> DeleteItemAsync(int id, CancellationToken ct = default)
    {
        var entity = await _db.IngredientNutritionCatalog.FirstOrDefaultAsync(i => i.Id == id, ct);
        if (entity is null) return false;

        entity.IsActive = false;
        await _db.SaveChangesAsync(ct);
        return true;
    }

    private static IngredientNutritionItemDto MapItem(IngredientNutritionCatalogItem item) => new()
    {
        Id = item.Id,
        CategoryId = item.CategoryId,
        CategoryCode = item.Category?.Code ?? string.Empty,
        CategoryName = item.Category?.Name ?? string.Empty,
        Name = item.Name,
        NamePl = item.NamePl,
        CaloriesPer100G = item.CaloriesPer100G,
        ProteinGPer100G = item.ProteinGPer100G,
        FatGPer100G = item.FatGPer100G,
        CarbsGPer100G = item.CarbsGPer100G,
        FiberGPer100G = item.FiberGPer100G,
    };
}
