using Managing.Application.Abstractions.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using static Managing.Common.Enums;

namespace Managing.Application.Workers;

public abstract class BaseWorker<T> : BackgroundService where T : class
{
    private readonly IServiceProvider _serviceProvider;
    private readonly WorkerType _workerType;
    protected readonly ILogger<T> _logger;
    protected readonly TimeSpan _delay;
    private int _executionCount;

    protected BaseWorker(
        WorkerType workerType,
        ILogger<T> logger,
        TimeSpan timeSpan,
        IServiceProvider serviceProvider)
    {
        _workerType = workerType;
        _logger = logger;
        _delay = timeSpan == TimeSpan.Zero ? TimeSpan.FromMinutes(1) : timeSpan;
        _serviceProvider = serviceProvider;
        _executionCount = 0;
    }

    protected override async Task ExecuteAsync(CancellationToken cancellationToken)
    {
        try
        {
            _logger.LogInformation($"[{_workerType}] Starting");
            using (var scope = _serviceProvider.CreateScope())
            {
                var workerService = scope.ServiceProvider.GetRequiredService<IWorkerService>();
                var worker = await workerService.GetWorker(_workerType);

                if (worker == null)
                {
                    await workerService.InsertWorker(_workerType, _delay);
                }
                else
                {
                    _logger.LogInformation(
                        $"[{_workerType}] Last run : {worker.LastRunTime} - Execution Count : {worker.ExecutionCount}");
                    _executionCount = worker.ExecutionCount;
                }
            }

            cancellationToken.Register(() => _logger.LogInformation($"[{_workerType}] Stopping"));

            while (!cancellationToken.IsCancellationRequested)
            {
                using (var scope = _serviceProvider.CreateScope())
                {
                    var workerService = scope.ServiceProvider.GetRequiredService<IWorkerService>();
                    var worker = await workerService.GetWorker(_workerType);

                    await Run(cancellationToken);
                    _executionCount++;
                    await workerService.UpdateWorker(_workerType, _executionCount);
                }

                _logger.LogInformation($"[{_workerType}] Run ok. Next run at : {DateTime.UtcNow.Add(_delay)}");
                await Task.Delay(_delay);
            }

            _logger.LogInformation($"[{_workerType}] Stopped");
        }
        catch (Exception ex)
        {
            SentrySdk.CaptureException(ex);
            _logger.LogError($"Error : {ex.Message}");
        }
    }

    protected abstract Task Run(CancellationToken cancellationToken);
}