using Microsoft.Extensions.Logging;
using PARR.Core.Services.MatchingStatusService;
using PARR.Domain.Cache.Models;
using PARR.Domain.Entities.Base.History;
using PARR.Domain.Enums;
using PARR.TemplateMatcher.Services.GroupedSync;
using PARR.TemplateMatcher.Services.Implementations.GroupedSync;
using PARR.TemplateMatcher.Services.Interfaces;
using System.Diagnostics;

namespace PARR.TemplateMatcher.Services.Implementations;

internal class GroupedTemplateSynchronizer : ITemplateSynchronizer
{
    private readonly IEnumerable<IGroupedSyncStage> _readStages;
    private readonly IEnumerable<IGroupedSyncWriteStage> _writeStages;
    private readonly IMatchingStatusService _matchingStatusService;
    private readonly ILogger<GroupedTemplateSynchronizer> _logger;

    public GroupedTemplateSynchronizer(
        IEnumerable<IGroupedSyncStage> readStages,
        IEnumerable<IGroupedSyncWriteStage> writeStages,
        IMatchingStatusService matchingStatusService,
        ILogger<GroupedTemplateSynchronizer> logger
        )
    {
        _readStages = readStages;
        _writeStages = writeStages;
        _matchingStatusService = matchingStatusService;
        _logger = logger;
    }

    public async Task SyncTemplatesForJobGroupAsync(Guid jobGroupId, HistoryInitiator initiator)
    {
        _logger.LogInformation("Начало синхронизации шаблонов для JobGroup {JobGroupId}", jobGroupId);

        var existingStatus = await _matchingStatusService.GetStatusAsync(jobGroupId, SyncTaskEntityTypeEnum.JobGroup);
        if (existingStatus.DetailsJobGroups?.Count > 0)
        {
            _logger.LogWarning("Синхронизация для JobGroup {JobGroupId} уже запущена. Пропускаем.", jobGroupId);
            return;
        }

        await SetStatusAsync(jobGroupId, "Начало синхронизации");

        var totalSw = Stopwatch.StartNew();

        try
        {
            var context = new GroupedSyncContext { JobGroupId = jobGroupId, Initiator = initiator };

            foreach (var stage in _readStages)
            {
                var stageSw = Stopwatch.StartNew();
                await stage.ExecuteAsync(context);
                stageSw.Stop();
                _logger.LogDebug("[Perf] JobGroup '{JobGroupName}' ({JobGroupId}) | Этап: {Stage} | Время: {Ms} мс",
                    context.JobGroupName, jobGroupId, stage.StageName, stageSw.ElapsedMilliseconds);
            }

            foreach (var stage in _writeStages)
            {
                var stageSw = Stopwatch.StartNew();
                await stage.ExecuteAsync(context);
                stageSw.Stop();
                _logger.LogDebug("[Perf] JobGroup '{JobGroupName}' ({JobGroupId}) | Этап: {Stage} | Время: {Ms} мс",
                    context.JobGroupName, jobGroupId, stage.StageName, stageSw.ElapsedMilliseconds);
            }

            totalSw.Stop();
            _logger.LogInformation("[Perf] JobGroup '{JobGroupName}' ({JobGroupId}) | ИТОГО: {TotalMs} мс",
                context.JobGroupName, jobGroupId, totalSw.ElapsedMilliseconds);

            await SetStatusAsync(jobGroupId, "Синхронизация завершена успешно");
            await _matchingStatusService.DeleteMatchingStatusAsync(jobGroupId, SyncTaskEntityTypeEnum.JobGroup);
            _logger.LogInformation("Синхронизация шаблонов завершена для JobGroup '{JobGroupName}' ({JobGroupId})",
                context.JobGroupName, jobGroupId);
        }
        catch (GroupedSyncEarlyExitException ex)
        {
            totalSw.Stop();
            _logger.LogInformation("JobGroup {JobGroupId}: {Reason} ({ElapsedMs} мс)",
                jobGroupId, ex.Reason, totalSw.ElapsedMilliseconds);
            await SetStatusAsync(jobGroupId, ex.Reason);
            await _matchingStatusService.DeleteMatchingStatusAsync(jobGroupId, SyncTaskEntityTypeEnum.JobGroup);
        }
        catch (Exception ex)
        {
            totalSw.Stop();
            _logger.LogError(ex, "Ошибка при синхронизации JobGroup {JobGroupId} через {ElapsedMs} мс",
                jobGroupId, totalSw.ElapsedMilliseconds);
            await SetStatusAsync(jobGroupId, $"Ошибка: {ex.Message}");
            throw;
        }
    }

    public Task SyncTemplatesForJobAsync(Guid jobId, HistoryInitiator initiator)
    {
        _logger.LogWarning("GroupedTemplateSynchronizer: SyncTemplatesForJob вызван для JobId {JobId}. Это не поддерживаемая операция.", jobId);
        return Task.CompletedTask;
    }

    public Task UpdateTemplatesForJobAsync(Guid jobId, HistoryInitiator initiator)
    {
        _logger.LogWarning("GroupedTemplateSynchronizer: UpdateTemplatesForJob вызван для JobId {JobId}. Это не поддерживаемая операция.", jobId);
        return Task.CompletedTask;
    }

    private async Task SetStatusAsync(Guid jobGroupId, string comment)
    {
        var status = new MatchingStatusItemDto
        {
            DateStart = DateTimeOffset.UtcNow,
            Action = TemplateMatcherActionEnum.Sync,
            Comment = comment
        };
        await _matchingStatusService.SetMatchingStatusAsync(
            jobGroupId, SyncTaskEntityTypeEnum.JobGroup,
            new MatchingStatusItem { Data = status, Timestamp = DateTimeOffset.UtcNow, Source = nameof(GroupedTemplateSynchronizer) },
            TimeSpan.FromMinutes(30));
    }
}