using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PARR.Core.Common.Interfaces;
using PARR.Core.Repositories.Interfaces.Unit;
using PARR.Core.Services.UnitFilterService.Matchers.Interfaces;
using PARR.Domain.Cache.Models;

namespace PARR.Core.Services.UnitFilterService.Matchers;

/// <summary>
/// Находит ID юнитов по маске имени через Redis-кэш с fallback на БД.
/// </summary>
internal class UnitNameResolver : IUnitNameResolver
{
    private readonly IRedisCacheService cacheService;
    private readonly IUnitRepository unitRepository;
    private readonly ILogger<UnitNameResolver> logger;

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

    public async Task<List<Guid>> ResolveAsync(string unitFilterMask, CancellationToken ct = default)
    {
        var cacheKey = cacheService.GetKey(new[] { "unit filter", "unit name mask" }, new[] { unitFilterMask });

        var cachedData = await cacheService.GetCachedDataAsync<UnitFilterIds>(cacheKey, true);
        if (cachedData != null)
        {
            logger.LogDebug("UnitNameResolver: маска '{Mask}' найдена в кэше ({Count} юнитов)",
                unitFilterMask, cachedData.Data.UnitIds.Count);
            return cachedData.Data.UnitIds;
        }

        var dbValueMask = NormalizeLikeMask(unitFilterMask);

        var initialUnitIds = await unitRepository.GetInitialUnitIds(dbValueMask).ToListAsync(ct);

        var toCache = new UnitFilterIds
        {
            Data = new UnitFilterIdsDto { UnitIds = initialUnitIds },
            Timestamp = DateTimeOffset.UtcNow,
            Source = GetType().Name
        };

        await cacheService.SetCachedDataAsync(cacheKey, toCache, TimeSpan.FromHours(1), true);

        logger.LogDebug("UnitNameResolver: маска '{Mask}' загружена из БД и сохранена в кэш ({Count} юнитов)",
            unitFilterMask, initialUnitIds.Count);

        return initialUnitIds;
    }

    /// <summary>
    /// Обрабатывает маску LIKE для корректной работы с SQL
    /// </summary>
    private static string NormalizeLikeMask(string valueMask)
    {
        if (string.IsNullOrWhiteSpace(valueMask))
            return valueMask;

        valueMask = valueMask.Trim();
        bool isStartsWith = valueMask.EndsWith("%") && !valueMask.EndsWith("%%");
        bool isEndsWith = valueMask.StartsWith("%") && !valueMask.StartsWith("%%");

        if (isStartsWith && isEndsWith)
            return $"%{valueMask.Trim('%')}%";
        else if (isStartsWith)
            return $"{valueMask.TrimEnd('%')}%";
        else if (isEndsWith)
            return $"%{valueMask.TrimStart('%')}";
        else
            return valueMask;
    }
}