using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PARR.Core.Repositories.Interfaces.Unit;
using PARR.Core.Services.UnitFilterService.Matchers.Interfaces;
using PARR.Domain.Entities.JobEntities;

namespace PARR.Core.Services.UnitFilterService.Matchers;

/// <summary>
/// Сопоставляет юниты с фильтрами по атрибутам.
/// </summary>
internal class UnitFieldMatcher : IUnitFieldMatcher
{
    private const int chunkSize = 200;
    private readonly IUnitRepository unitRepository;
    private readonly ILogger<UnitFieldMatcher> logger;

    public UnitFieldMatcher(
        IUnitRepository unitRepository,
        ILogger<UnitFieldMatcher> logger)
    {
        this.unitRepository = unitRepository;
        this.logger = logger;
    }

    public async Task<List<Guid>> MatchAsync(
        IReadOnlyList<Guid> unitIds,
        IEnumerable<JobFieldFilter> fieldFilters,
        CancellationToken ct = default)
    {
        var filters = fieldFilters?.ToList();
        if (filters == null || filters.Count == 0)
            return new List<Guid>(unitIds);

        logger.LogDebug("UnitFieldMatcher: вход {UnitCount} юнитов, фильтров: {FilterCount}",
            unitIds.Count, filters.Count);

        var result = new List<Guid>(unitIds.Count);

        foreach (var chunk in unitIds.Chunk(chunkSize))
        {
            var query = unitRepository.Get().AsNoTracking()
                .Where(u => chunk.Contains(u.Id));

            foreach (var fieldFilter in filters)
            {
                var valueMask = fieldFilter.ValueMask?.Trim();
                if (string.IsNullOrEmpty(valueMask))
                    continue;

                query = unitRepository.GetUnitByFieldAndValue(
                    query, fieldFilter.FieldId, fieldFilter.ValueMask!, fieldFilter.IsInverse);
            }

            var chunkResult = await query.Select(u => u.Id).ToListAsync(ct);
            result.AddRange(chunkResult);
        }

        logger.LogDebug("UnitFieldMatcher: выход {UnitCount} юнитов", result.Count);

        return result;
    }
}