using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PARR.Core.Repositories.Interfaces.Unit;
using PARR.DAL.Context;
using PARR.Domain.Entities.Unit;

namespace PARR.DAL.Repositories.Unit
{
    internal class UnitInValueRepository : IUnitInValueRepository
    {
        private readonly ILogger<UnitInValueRepository> logger;
        private readonly DataContext dataContext;

        public UnitInValueRepository(
            ILogger<UnitInValueRepository> logger,
            DataContext dataContext
            )
        {
            this.logger = logger;
            this.dataContext = dataContext;
        }

        public async Task<List<UnitInValue>> GetByUnitIdAsync(Guid unitId, CancellationToken ct = default)
        {
            return await dataContext.UnitInValues.AsNoTracking()
                    .Include(t => t.Value)
                    .Where(uv => uv.UnitId == unitId)
                    .ToListAsync(ct);
        }

        public async Task<List<UnitInValue>> GetByUnitIdsAsync(IEnumerable<Guid> unitIds, CancellationToken ct = default)
        {
            return await dataContext.UnitInValues.AsNoTracking()
                    .Include(t => t.Value)
                    .Where(uv => unitIds.Contains(uv.UnitId))
                    .ToListAsync(ct);
        }


        public async Task<List<(string FieldName, string? Value)>> GetFieldValuesAsync(
            Guid unitId,
            IReadOnlyCollection<string> aihitNames
            , CancellationToken ct = default)
        {
            if (aihitNames == null || aihitNames.Count == 0)
                return new List<(string, string?)>();

            var keyValuePairs = await dataContext.UnitInValues
                .AsNoTracking()
                .AsSplitQuery()
                .Where(uiv => uiv.UnitId == unitId
                           && uiv.Field != null
                           && uiv.Value != null
                           && aihitNames.Contains(uiv.Field.AihitName.ToUpper()))
                .Select(uiv => new { Key = uiv.Field!.AihitName.ToUpper(), Value = uiv.Value!.Value })
                .ToListAsync(ct);

            // Журналируем если не нашли поля
            var foundFieldNames = keyValuePairs.Select(kvp => kvp.Key).ToHashSet(StringComparer.OrdinalIgnoreCase);
            var missing = aihitNames
                .Where(name => !foundFieldNames.Contains(name.ToUpper()))
                .ToList();
            if (missing.Any())
            {
                logger.LogDebug("UnitInValueService: поля не найдены для unitId={UnitId}: {Fields}",
                    unitId, string.Join(", ", missing));
            }

            return keyValuePairs.Select(kvp => (kvp.Key, kvp.Value)).ToList();
        }


        public async Task<List<UnitInValue>> GetByUnitIdsAndFieldIdsAsync(IEnumerable<Guid> unitIds, IEnumerable<Guid> fieldIds, CancellationToken ct = default)
        {
            var unitIdSet = unitIds.ToHashSet();
            var fieldIdSet = fieldIds.ToHashSet();

            return await dataContext.UnitInValues
                .AsNoTracking()
                .Include(uv => uv.Value)
                .Where(uv => unitIdSet.Contains(uv.UnitId) && fieldIdSet.Contains(uv.FieldId))
                .ToListAsync(ct);
        }

        public IQueryable<UnitInValue> Get()
        {
            return dataContext.UnitInValues;
        }

        public async Task<string?> GetMostFrequentValueForFieldAsync(List<Guid> unitIds, string fieldName, CancellationToken ct)
        {
            if (unitIds == null || !unitIds.Any() || string.IsNullOrWhiteSpace(fieldName))
            {
                logger.LogDebug("GetMostFrequentValueForFieldAsync: пустой список юнитов или имя поля. unitIds count: {Count}, fieldName: {FieldName}", unitIds?.Count ?? 0, fieldName);
                return null;
            }

            logger.LogDebug("Поиск наиболее частого значения для поля '{FieldName}' среди {Count} юнитов.", fieldName, unitIds.Count);

            var result = await dataContext.UnitInValues
                .AsNoTracking()
                .Where(uv =>
                    unitIds.Contains(uv.UnitId)
                )
                .Join(
                    dataContext.UnitFields,
                    uv => uv.FieldId,
                    f => f.Id,
                    (uv, f) => new { uv, f }
                )
                .Where(x =>
                    EF.Functions.ILike(x.f.AihitName, fieldName)
                )
                .Join(
                    dataContext.UnitFieldValues,
                    x => x.uv.ValueId,
                    v => v.Id,
                    (x, v) => new { x.uv.UnitId, v.Value }
                )
                .Where(x => !string.IsNullOrWhiteSpace(x.Value))
                .GroupBy(x => x.Value)
                .Select(g => new { Value = g.Key, Count = g.Count() })
                .OrderByDescending(x => x.Count)
                .ThenBy(x => x.Value)
                .FirstOrDefaultAsync(ct);

            var mostFrequentValue = result?.Value;
            logger.LogDebug("Наиболее частое значение для поля '{FieldName}': {Value}", fieldName, mostFrequentValue);
            return mostFrequentValue;
        }


        public IQueryable<Guid> GetMatchingTargetIds(Guid fieldId, string valueMask)
        {
            return Get()
               .AsNoTracking()
               .Where(uiv => uiv.FieldId == fieldId)
               .Where(uiv => EF.Functions.ILike(uiv.Value.Value, valueMask))
               .Select(uiv => uiv.UnitId)
               .Distinct();
        }


    }
}
