using Microsoft.Extensions.Logging;
using PARR.Core.Common.Interfaces;
using PARR.Core.Repositories.Interfaces.Unit;
using PARR.Core.Services.Shortcodes.Enums;
using PARR.Core.Services.Shortcodes.Models;
using PARR.Domain.Cache.Models;
using System.Text.RegularExpressions;

namespace PARR.Core.Services.Shortcodes.Handlers;

internal class MaxShortcodeHandler : IShortcodeHandler
{
    private readonly IUnitInValueRepository unitInValueRepo;
    private readonly IRedisCacheService cacheService;
    private readonly ILogger<MaxShortcodeHandler> logger;

    public int Order => 40;
    private static readonly Regex _pattern = new(@"%МАКС:([^%]+)%", RegexOptions.Compiled | RegexOptions.IgnoreCase);
    public Regex Pattern => _pattern;

    public ShortcodeDataRequirementsEnum Requirements =>
        ShortcodeDataRequirementsEnum.Job |
        ShortcodeDataRequirementsEnum.JobGroup |
        ShortcodeDataRequirementsEnum.UnitsInTemplate;

    public MaxShortcodeHandler(
        IUnitInValueRepository unitInValueRepo,
        IRedisCacheService cacheService,
        ILogger<MaxShortcodeHandler> logger)
    {
        this.unitInValueRepo = unitInValueRepo;
        this.cacheService = cacheService;
        this.logger = logger;
    }

    public async Task<string> ResolveAsync(string input, TemplateForShortcode template, string caller, CancellationToken ct = default)
    {
        var matches = Pattern.Matches(input);
        if (matches.Count == 0) return input;

        // Извлекаем уникальные имена полей, чтобы не ходить в кэш/БД дважды для одинаковых шорткодов
        var uniqueFields = matches.Cast<Match>()
            .Select(m => m.Value.Trim('%').Split(':', 2)[1].Trim())
            .Distinct(StringComparer.OrdinalIgnoreCase)
            .ToList();

        var resolved = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        foreach (var field in uniqueFields)
        {
            resolved[$"%МАКС:{field}%"] = await GetMaxValueAsync(template, field, caller, ct);
        }

        var result = input;
        foreach (Match m in matches)
        {
            if (resolved.TryGetValue(m.Value, out var val))
                result = result.Replace(m.Value, val, StringComparison.OrdinalIgnoreCase);
        }

        return result;
    }

    private async Task<string> GetMaxValueAsync(TemplateForShortcode template, string fieldName, string caller, CancellationToken ct)
    {
        // Guard: данные должны быть подготовлены оркестратором согласно Requirements
        if (template.Job?.Group == null || template.UnitId == Guid.Empty)
            return "Нет данных";

        if (template.UnitsInTemplate.Count == 0)
        {
            logger.LogDebug("[{Caller}] %МАКС:{Field}% пропущен: UnitsInTemplate пуст для шаблона {TemplateId}.", caller, fieldName, template.Id);
            return "Нет данных";
        }

        var cacheKey = cacheService.GetKey(
            new[] { "grouped", "shortcode", $"{template.Job.Group.Id:N}", $"{template.UnitId:N}" },
            new[] { $"%МАКС:{fieldName}%" });

        var cached = await cacheService.GetCachedDataAsync<GroupedShortcode>(cacheKey);
        if (cached != null) return cached.Data.Value;

        var unitIds = template.UnitsInTemplate.Select(u => u.UnitId).Distinct().ToList();
        var value = await unitInValueRepo.GetMostFrequentValueForFieldAsync(unitIds, fieldName, ct);

        if (!string.IsNullOrEmpty(value))
        {
            await cacheService.SetCachedDataAsync(cacheKey, new GroupedShortcode
            {
                Data = new GroupedShortcodeDto { Value = value },
                Timestamp = DateTimeOffset.UtcNow,
                Source = nameof(MaxShortcodeHandler)
            }, TimeSpan.FromHours(1));
        }

        return value ?? "Нет данных";
    }
}