using SIGCM2.Application.Rubros.Dtos;
using SIGCM2.Domain.Entities;

namespace SIGCM2.Application.Rubros.Common;

/// <summary>
/// Builds an N-ary tree from a flat list of Rubro entities in O(n) time.
/// Algorithm: (1) optionally filter inactivos, (2) group by ParentId into a dictionary,
/// (3) recursively assemble roots (ParentId==null) attaching children sorted by Orden ASC.
/// </summary>
public static class RubroTreeBuilder
{
    public static IReadOnlyList<RubroTreeNodeDto> Build(
        IEnumerable<Rubro> flat,
        bool incluirInactivos,
        IReadOnlyDictionary<int, int> avisoCounts)
    {
        var filtered = incluirInactivos
            ? flat.ToList()
            : flat.Where(r => r.Activo).ToList();

        // Group by ParentId → each bucket sorted by Orden ASC
        // Use ToLookup (handles the int? key safely) instead of ToDictionary
        var byParent = filtered.ToLookup(r => r.ParentId);

        RubroTreeNodeDto Map(Rubro r)
        {
            var children = byParent[(int?)r.Id]
                .OrderBy(x => x.Orden)
                .Select(Map)
                .ToList();

            return new RubroTreeNodeDto(
                Id: r.Id,
                Nombre: r.Nombre,
                Orden: r.Orden,
                Activo: r.Activo,
                ParentId: r.ParentId,
                TarifarioBaseId: r.TarifarioBaseId,
                TieneAvisos: avisoCounts.GetValueOrDefault(r.Id, 0) > 0,
                Hijos: children);
        }

        return byParent[null]
            .OrderBy(r => r.Orden)
            .Select(Map)
            .ToList();
    }
}
