using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PARR.Core.Repositories.Interfaces;
using PARR.Domain.Entities;
using PARR.Domain.Entities.Base.History;
using PARR.TemplateMatcher.Services.Interfaces;

namespace PARR.TemplateMatcher.Services.Implementations;

internal class TemplateReuser : ITemplateReuser
{
    private readonly ILogger<TemplateReuser> logger;
    private readonly ITemplateRepository templateService;

    public TemplateReuser(
        ILogger<TemplateReuser> logger,
        ITemplateRepository templateService)
    {
        this.logger = logger;
        this.templateService = templateService;
    }

    public async Task<Template?> TryReuseOneUnusedTemplateAsync(
        Guid jobId,
        Guid unitId,
        HistoryInitiator initiator,
        int maxAttempts = 3)
    {
        for (int attempt = 1; attempt <= maxAttempts; attempt++)
        {
            try
            {
                // Атомарно резервируем один шаблон через DAL
                var templateId = await templateService.ReserveUnusedTemplateAsync(unitId, initiator);

                if (templateId == null)
                {
                    logger.LogDebug("Нет доступных Unused-шаблонов для переиспользования (попытка {Attempt}).", attempt);
                    return null;
                }

                // Загружаем зарезервированный шаблон
                var template = await templateService.Get()
                    .AsNoTracking()
                    .Include(t=>t.Unit)
                    .Include(t=>t.Job)
                        .ThenInclude(t=>t!.Tnk)
                    .Include(t => t.Job)
                        .ThenInclude(t => t!.Group)
                            .ThenInclude(t=>t!.GroupType)
                    .FirstOrDefaultAsync(t => t.Id == templateId);

                if (template == null)
                {
                    logger.LogWarning("Зарезервированный шаблон {TemplateId} не найден при загрузке.", templateId);
                    continue; 
                }

                logger.LogInformation(
                    "Успешно захвачен шаблон {TemplateId} (старый Job {OldJobId}) для нового Job {NewJobId}, Unit {UnitId} (попытка {Attempt}).",
                    template.Id, template.JobId, jobId, unitId, attempt);

                return template;
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "Ошибка при попытке захвата шаблона (попытка {Attempt}).", attempt);

                if (attempt == maxAttempts)
                    throw; 

                // Небольшая задержка перед повтором
                await Task.Delay(Random.Shared.Next(10, 50));
            }
        }

        return null;
    }
}