using Hcs.WebApp.Data.Hcs;
using Microsoft.EntityFrameworkCore;

namespace Hcs.WebApp.Services
{
    public class HeadquartersService(IDbContextFactory<HcsDbContext> factory) : HcsServiceBase(factory)
    {
        public async Task<bool> HasActiveCampaignAsync(Campaign.CampaignType type)
        {
            using var context = GetNewContext();
            return await context.Campaigns.AnyAsync(x => x.Type == type && !x.EndedAt.HasValue);
        }

        public async Task<IEnumerable<Campaign>> GetCampaignsAsync()
        {
            using var context = GetNewContext();
            return await context.Campaigns.ToListAsync();
        }

        public async Task<IEnumerable<Campaign>> GetNotEndedCampaignsAsync()
        {
            using var context = GetNewContext();
            return await (from campaign in context.Campaigns
                          where !campaign.EndedAt.HasValue
                          select campaign).ToListAsync();
        }

        public async Task<IEnumerable<Operation>> GetNotExecutedRemoteOperationsAsync()
        {
            using var context = GetNewContext();
            var query = from operation in context.Operations
                        where string.IsNullOrEmpty(operation.MessageGuid) && !operation.EndedAt.HasValue
                        select operation;
            var result = await query.ToListAsync();
            return result.Where(x => x.Kind == Operation.OperationKind.Remote);
        }

        public async Task<IEnumerable<Operation>> GetResultWaitingRemoteOperationsAsync()
        {
            using var context = GetNewContext();
            var query = from operation in context.Operations
                        where !string.IsNullOrEmpty(operation.MessageGuid) && !operation.EndedAt.HasValue
                        select operation;
            var result = await query.ToListAsync();
            return result.Where(x => x.Kind == Operation.OperationKind.Remote);
        }

        public async Task<IEnumerable<Operation>> GetNotCompletedParseOperationsAsync()
        {
            using var context = GetNewContext();
            var query = from operation in context.Operations
                        where !operation.EndedAt.HasValue
                        select operation;
            var result = await query.ToListAsync();
            return result.Where(x => x.Kind == Operation.OperationKind.Parse);
        }

        public async Task<ICollection<Operation>> GetOperationsAsync()
        {
            using var context = GetNewContext();
            return await context.Operations.ToListAsync();
        }

        public async Task<ICollection<Operation>> GetOperationsAsync(int campaignId)
        {
            using var context = GetNewContext();
            return await (from operation in context.Operations
                          where operation.CampaignId == campaignId
                          select operation).ToListAsync();
        }

        public async Task<Campaign> InitiateCampaignAsync(Campaign.CampaignType type, string initiatorId)
        {
            using var context = GetNewContext();
            var campaign = new Campaign()
            {
                Type = type,
                InitiatorId = initiatorId,
                CreatedAt = DateTime.UtcNow
            };
            await context.Campaigns.AddAsync(campaign);
            await context.SaveChangesAsync();
            return campaign;
        }

        public async Task<IEnumerable<Operation>> InitiateOperationsAsync(HcsDbContext context, int count, int campaignId, Operation.OperationType type)
        {
            var operations = new List<Operation>();
            for (var i = 0; i < count; i++)
            {
                operations.Add(new Operation()
                {
                    CampaignId = campaignId,
                    Type = type,
                    CreatedAt = DateTime.UtcNow
                });
            }
            await context.Operations.AddRangeAsync(operations);
            await context.SaveChangesAsync();
            return operations;
        }

        public async Task SetCampaignStartedAsync(HcsDbContext context, int campaignId, DateTime startedAt)
        {
            var campaign = await context.Campaigns.FirstOrDefaultAsync(x => x.Id == campaignId);
            if (campaign != null)
            {
                campaign.StartedAt = startedAt;

                await context.SaveChangesAsync();
            }
        }

        public async Task SetOperationStartedAsync(int operationId, DateTime startedAt)
        {
            using var context = GetNewContext();
            var operation = await context.Operations.FirstOrDefaultAsync(x => x.Id == operationId);
            if (operation != null)
            {
                operation.StartedAt = startedAt;

                await context.SaveChangesAsync();
            }
        }

        public async Task SetCampaignEndedAsync(int campaignId, DateTime endedAt)
        {
            using var context = GetNewContext();
            await SetCampaignEndedAsync(context, campaignId, endedAt);
        }

        public async Task SetCampaignEndedAsync(HcsDbContext context, int campaignId, DateTime endedAt)
        {
            var campaign = await context.Campaigns.FirstOrDefaultAsync(x => x.Id == campaignId);
            if (campaign != null)
            {
                campaign.EndedAt = endedAt;

                await context.SaveChangesAsync();
            }
        }

        public async Task SetCampaignEndedWithFailAsync(int campaignId, DateTime endedAt, string failureReason)
        {
            using var context = GetNewContext();
            var campaign = await context.Campaigns.FirstOrDefaultAsync(x => x.Id == campaignId);
            if (campaign != null)
            {
                campaign.EndedAt = endedAt;
                campaign.FailureReason = failureReason;

                await context.SaveChangesAsync();
            }
        }

        public async Task SetOperationEndedAsync(HcsDbContext context, int operationId, DateTime endedAt)
        {
            var operation = await context.Operations.FirstOrDefaultAsync(x => x.Id == operationId);
            if (operation != null)
            {
                operation.EndedAt = endedAt;

                await context.SaveChangesAsync();
            }
        }

        public async Task SetOperationEndedWithFailAsync(int operationId, DateTime endedAt, string failureReason)
        {
            using var context = GetNewContext();
            var operation = await context.Operations.FirstOrDefaultAsync(x => x.Id == operationId);
            if (operation != null)
            {
                operation.EndedAt = endedAt;
                operation.FailureReason = failureReason;

                await context.SaveChangesAsync();
            }
        }

        public async Task SetOperationMessageGuidAsync(int operationId, string messageGuid)
        {
            using var context = GetNewContext();
            var operation = await context.Operations.FirstOrDefaultAsync(x => x.Id == operationId);
            if (operation != null)
            {
                operation.MessageGuid = messageGuid;

                await context.SaveChangesAsync();
            }
        }

        public async Task UpdateCampaignStepAndProgressAsync(Campaign campaign)
        {
            using var context = GetNewContext();
            await UpdateCampaignStepAndProgressAsync(context, campaign);
        }

        public async Task UpdateCampaignStepAndProgressAsync(HcsDbContext context, Campaign campaign)
        {
            var targetCampaign = await context.Campaigns.FirstOrDefaultAsync(x => x.Id == campaign.Id);
            if (targetCampaign != null)
            {
                targetCampaign.Step = campaign.Step;
                targetCampaign.Progress = campaign.Progress;

                await context.SaveChangesAsync();
            }
        }
    }
}
