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

namespace PARR.Core.Services.Shortcodes.Handlers;

internal class GroupedFieldShortcodeHandler : IShortcodeHandler
{
    private readonly IUnitRepository unitRepo;
    private readonly IUnitFieldValueRepository fieldValueRepo;
    private readonly ITemplateRepository templateRepo;
    private readonly ILogger<GroupedFieldShortcodeHandler> logger;

    public int Order => 30;

    private static readonly Regex _pattern = new(@"%ГР_ПОЛЕ-ПН%", RegexOptions.Compiled | RegexOptions.IgnoreCase);
    public Regex Pattern => _pattern;

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

    public GroupedFieldShortcodeHandler(
        IUnitRepository unitRepo,
        IUnitFieldValueRepository fieldValueRepo,
        ITemplateRepository templateRepo,
        ILogger<GroupedFieldShortcodeHandler> logger)
    {
        this.unitRepo = unitRepo;
        this.fieldValueRepo = fieldValueRepo;
        this.templateRepo = templateRepo;
        this.logger = logger;
    }

    public async Task<string> ResolveAsync(string input, TemplateForShortcode template, string caller, CancellationToken ct = default)
    {
        if (!input.Contains("%ГР_ПОЛЕ-ПН%", StringComparison.OrdinalIgnoreCase)) return input;

        if (template.Job?.Group == null)
        {
            logger.LogWarning("[{Caller}] Job не содержит Group, необходимый для %ГР_ПОЛЕ-ПН%. Шорткод пропущен.", caller);
            return input.Replace("%ГР_ПОЛЕ-ПН%", string.Empty, StringComparison.OrdinalIgnoreCase);
        }

        var unitsList = template.UnitsInTemplate;
        if (unitsList.Count == 0)
        {
            // Данные должны быть загружены оркестратором. Если пусто — значит в БД действительно нет связей.
            return input.Replace("%ГР_ПОЛЕ-ПН%", string.Empty, StringComparison.OrdinalIgnoreCase);
        }

        var unitIds = unitsList.Select(u => u.UnitId).Distinct().ToList();
        var fieldValueIds = unitsList.Select(u => u.UnitFieldValueId).Distinct().ToList();

        var unitNames = await unitRepo.Get()
            .AsNoTracking()
            .Where(u => unitIds.Contains(u.Id))
            .ToDictionaryAsync(u => u.Id, u => u.Name ?? u.Id.ToString(), ct);

        var fieldValueStrings = await fieldValueRepo.Get()
            .AsNoTracking()
            .Where(fv => fieldValueIds.Contains(fv.Id))
            .ToDictionaryAsync(fv => fv.Id, fv => fv.Value ?? string.Empty, ct);

        var lines = unitsList.Select((uit, i) =>
        {
            var uName = unitNames.GetValueOrDefault(uit.UnitId, $"(UnitId={uit.UnitId})");
            var fVal = fieldValueStrings.GetValueOrDefault(uit.UnitFieldValueId, string.Empty);
            return $"{i + 1}. {uName} ({fVal})";
        });

        return input.Replace("%ГР_ПОЛЕ-ПН%", string.Join("\n", lines), StringComparison.OrdinalIgnoreCase);
    }
}