using Hcs.WebApp.BackgroundServices.CampaignManagers;
using Hcs.WebApp.Data.Hcs;
using Hcs.WebApp.Services;

namespace Hcs.WebApp.BackgroundServices
{
    public class CampaignManagementService(
        CampaignManagementState campaignManagementState,
        OperationExecutionState operationExecutionState,
        ResultWaitState resultWaitState,
        ManagerFactory managerFactory,
        IServiceScopeFactory scopeFactory) : BackgroundService
    {
        private const int STATES_WAIT_TIME = 1000;
        private const int ITERATION_TIME = 1000;
        private const int SLEEP_TIME = 30000;

        private readonly CampaignManagementState campaignManagementState = campaignManagementState;
        private readonly OperationExecutionState operationExecutionState = operationExecutionState;
        private readonly ResultWaitState resultWaitState = resultWaitState;
        private readonly ManagerFactory managerFactory = managerFactory;
        private readonly IServiceScopeFactory scopeFactory = scopeFactory;
        private readonly List<IManager> managers = [];

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            await WaitForOtherStates();
            await InitializeStateAsync();

            while (!stoppingToken.IsCancellationRequested)
            {
                while (campaignManagementState.TryDequeueCampaign(out var campaign))
                {
                    if (stoppingToken.IsCancellationRequested) return;

                    var manager = managerFactory.CreateManager(campaign);
                    if (manager != null)
                    {
                        managers.Add(manager);
                    }
                    else
                    {
                        using var scope = scopeFactory.CreateScope();
                        var headquartersService = scope.ServiceProvider.GetRequiredService<HeadquartersService>();
                        await headquartersService.SetCampaignEndedWithFailAsync(campaign.Id, "Не удалось найти подходящий менеджер кампании");

                        campaignManagementState.InvokeOnCampaignEnded(campaign);
                    }
                }

                foreach (var manager in managers)
                {
                    try
                    {
                        await manager.ProcessAsync();
                    }
                    catch (Exception e)
                    {
                        await manager.EndWithFailAsync(e);
                    }

                    if (manager.State == IManager.ManagerState.Ended)
                    {
                        campaignManagementState.InvokeOnCampaignEnded(manager.Campaign);
                    }
                }

                managers.RemoveAll(x => x.State == IManager.ManagerState.Ended);

                if (managers.Count > 0)
                {
                    await Task.Delay(ITERATION_TIME, stoppingToken);
                }
                else
                {
                    await Task.Delay(SLEEP_TIME, stoppingToken);
                }
            }
        }

        private async Task WaitForOtherStates()
        {
            while (!operationExecutionState.Ready || !resultWaitState.Ready)
            {
                await Task.Delay(STATES_WAIT_TIME);
            }
        }

        private async Task InitializeStateAsync()
        {
            using var scope = scopeFactory.CreateScope();
            var headquartersService = scope.ServiceProvider.GetRequiredService<HeadquartersService>();

            var campaigns = await headquartersService.GetNotEndedCampaignsAsync();
            foreach (var campaign in campaigns)
            {
                campaignManagementState.EnqueueCampaign(campaign);
            }
        }
    }
}
