using MediatR;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using NetworkResurrector.Agent.PublishedLanguage.Dto;
using NetworkResurrector.Agent.Wrapper.Services;
using NetworkResurrector.Api.Domain.Constants;
using NetworkResurrector.Api.Domain.Repositories;
using NetworkResurrector.Api.PublishedLanguage.Commands;
using NetworkResurrector.Api.PublishedLanguage.Events;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace NetworkResurrector.Api.Application.CommandHandlers
{
    public class CancelMachineHandler : IRequestHandler<CancelAction, ActionCanceled>
    {
        private readonly ILogger<CancelMachineHandler> _logger;
        private readonly INetworkRepository _repository;
        private readonly IResurrectorAgentService _resurrectorAgentService;
        private readonly IConfiguration _configuration;

        public CancelMachineHandler(ILogger<CancelMachineHandler> logger, INetworkRepository repository, IResurrectorAgentService resurrectorAgentService, IConfiguration configuration)
        {
            _logger=logger;
            _repository=repository;
            _resurrectorAgentService=resurrectorAgentService;
            _configuration=configuration;
        }

        public async Task<ActionCanceled> Handle(CancelAction command, CancellationToken cancellationToken)
        {
            var powerConfiguration = await _repository.GetPowerActionConfiguration(command.MachineId, command.ActionId);
            _logger.LogDebug($"Start canceling action '{powerConfiguration.PowerAction.PowerActionCode}' for machine {command.MachineId}");

            var machine = await _repository.GetMachine(command.MachineId);

            //log activity

            var ipAddressOrMachineName = machine.IPv4Address ?? machine.MachineName;
            ActionCanceled result;

            switch (powerConfiguration.Performer.PerformerCode)
            {
                case PowerActionPerformers.NETWORK_RESURRECTOR_AGENT:
                    if (machine.Agent == null)
                        throw new Exception($"Cannot use network resurrector agent as cancel performer for action '{powerConfiguration.PowerAction.PowerActionCode}' and machine '{ipAddressOrMachineName}' because it is not configured.");

                    var owner = new ActionOwner(_configuration.GetValue<string>("Service:Code"));
                    var cancelResultByAgent = await _resurrectorAgentService.Cancel(ipAddressOrMachineName, machine.Agent.AgentPort, owner);
                    var status = cancelResultByAgent.Success ? $"Action '{powerConfiguration.PowerAction.PowerActionCode}' successfully canceled for machine '{ipAddressOrMachineName}'." : $"Action '{powerConfiguration.PowerAction.PowerActionCode}' could not be canceled for machine '{ipAddressOrMachineName}'.";
                    result = new ActionCanceled(cancelResultByAgent.Success, status);
                    break;

                default:
                    throw new Exception($"Power action performer {powerConfiguration.Performer.PerformerCode} is not implemented.");
            }

            _logger.LogDebug($"Action '{powerConfiguration.PowerAction.PowerActionCode}' cancellation finished for machine {command.MachineId}. Success: {result.Success}; Status: {result.Status}");

            return result;
        }
    }
}