using Microsoft.Extensions.Logging;
using PARR.Core.Services.UnitFilterService.Matchers.Interfaces;
using PARR.Core.Services.UnitFilterService.Models;
using PARR.Core.Services.UnitService.Interfaces;
using PARR.Domain.DTOs.UnitDto;

namespace PARR.Core.Services.UnitFilterService.Matchers;

/// <summary>
/// Загружает полные данные юнитов через IUnitService и формирует UnitFilterResultDto.
/// </summary>
internal class UnitFilterResultLoader : IUnitFilterResultLoader
{
    private readonly IUnitService unitService;
    private readonly ILogger<UnitFilterResultLoader> logger;

    public UnitFilterResultLoader(
        IUnitService unitService,
        ILogger<UnitFilterResultLoader> logger)
    {
        this.unitService = unitService;
        this.logger = logger;
    }

    public async Task<List<UnitFilterResultDto>> LoadAsync(
        List<UnitFilterMatchResult> contexts,
        CancellationToken ct = default)
    {
        if (contexts.Count == 0)
            return new List<UnitFilterResultDto>();

        // Собираем ВСЕ уникальные ID сразу
        var allRequiredUnitIds = new HashSet<Guid>();
        foreach (var ctx in contexts)
        {
            allRequiredUnitIds.Add(ctx.UnitId);
            foreach (var id in ctx.ValidParentIds) allRequiredUnitIds.Add(id);
            foreach (var id in ctx.ValidChildIds) allRequiredUnitIds.Add(id);
        }

        // Один вызов — UnitCacheService сам решает, как грузить
        var cachedUnitsMap = await unitService.GetWithCachingAsync(allRequiredUnitIds);

        var result = new List<UnitFilterResultDto>(contexts.Count);
        int missedCount = 0;

        foreach (var context in contexts)
        {
            ct.ThrowIfCancellationRequested();

            if (!cachedUnitsMap.TryGetValue(context.UnitId, out var unitInfo))
            {
                missedCount++;
                logger.LogWarning("Юнит {UnitId} не найден в кэше при формировании результата фильтрации.", context.UnitId);
                continue;
            }

            var dto = new UnitFilterResultDto
            {
                Id = unitInfo.Id,
                Name = unitInfo.Name,
                Values = unitInfo.Values.Select(v => new UnitValueDto
                {
                    FieldId = v.FieldId,
                    Value = v.Value
                }).ToList(),
                Parents = context.ValidParentIds
                    .Where(id => cachedUnitsMap.ContainsKey(id))
                    .Select(id => MapToRelatedUnitDto(cachedUnitsMap[id]))
                    .ToList(),
                Children = context.ValidChildIds
                    .Where(id => cachedUnitsMap.ContainsKey(id))
                    .Select(id => MapToRelatedUnitDto(cachedUnitsMap[id]))
                    .ToList()
            };

            result.Add(dto);
        }

        if (missedCount > 0)
        {
            logger.LogWarning("LoadAsync: {MissedCount} из {TotalCount} юнитов не найдены в кэше для Job фильтрации.",
                missedCount, contexts.Count);
        }

        return result;
    }

    /// <summary>
    /// Маппинг UnitInfo из кэша в RelatedUnitDto для родителей/детей
    /// </summary>
    private static RelatedUnitDto MapToRelatedUnitDto(UnitInfo unitInfo)
    {
        return new RelatedUnitDto
        {
            UnitId = unitInfo.Id,
            Name = unitInfo.Name,
            Values = unitInfo.Values.Select(v => new UnitValueDto
            {
                FieldId = v.FieldId,
                Value = v.Value
            }).ToList()
        };
    }
}