using Microsoft.Extensions.Logging;
using NetworkResurrector.Agent.Application.Services.Abstractions;
using NetworkResurrector.Agent.Domain.Models;
using System;
using System.Security.Principal;

namespace NetworkResurrector.Agent.Application.Services.Windows
{
    internal class WindowsPowerService : IPowerService
    {
        private readonly ILogger<WindowsPowerService> _logger;
        private readonly ICliService _cliService;

        public WindowsPowerService(ILogger<WindowsPowerService> logger, ICliService cliService)
        {
            _logger=logger;
            _cliService=cliService;
        }

        private string SetOptions(string arguments, PowerOptions options)
        {
            if (options == null)
                return arguments;

            if (options.Force)
                arguments = $"{arguments} -f";

            if (options.Delay.HasValue)
                arguments = $"{arguments} -t {options.Delay.Value}";

            return arguments;
        }

        private bool IsSystemUser()
        {
            bool isSystem;
#pragma warning disable CA1416 // Validate platform compatibility
            using (var identity = WindowsIdentity.GetCurrent())
            {
                isSystem = identity.IsSystem;
            }
#pragma warning restore CA1416 // Validate platform compatibility

            return isSystem;
        }

        private void ValidateLocalOrDomainUser()
        {
            var isSystem = IsSystemUser();
            if (isSystem)
                throw new Exception("This action is not available for system users.");
        }

        private void ManageExecutionResponse((bool success, string message) input)
        {
            var (success, message) = input;
            if (success)
                _logger.LogDebug(message);
            else
                throw new Exception(message);
        }

        public void Shutdown(PowerOptions options)
        {
            var arguments = "-s";
            arguments = SetOptions(arguments, options);
            _logger.LogInformation($"Shutdown arguments: {arguments}");
            var result =_cliService.Shutdown(arguments);
            ManageExecutionResponse(result);
        }

        public void Restart(PowerOptions options)
        {
            var arguments = "-r";
            arguments = SetOptions(arguments, options);
            _logger.LogInformation($"Restart arguments: {arguments}");
            var result = _cliService.Shutdown(arguments);
            ManageExecutionResponse(result);
        }

        public void Sleep(PowerOptions options)
        {
            if (options.Delay.HasValue)
            {
                _logger.LogWarning($"Sleep action does not accept delay.");
                options = new PowerOptions(null, options.Force);
            }

            var arguments = "-h";
            arguments = SetOptions(arguments, options);
            _logger.LogInformation($"Sleep arguments: {arguments}");
            var result =_cliService.Shutdown(arguments);
            ManageExecutionResponse(result);
        }

        public void Logout()
        {
            ValidateLocalOrDomainUser();
            var result = _cliService.Shutdown("-l");
            ManageExecutionResponse(result);
        }

        public void Lock()
        {
            ValidateLocalOrDomainUser();
            var command = "rundll32.exe user32.dll,LockWorkStation";
            var result = _cliService.Execute(command);
            ManageExecutionResponse(result);
        }

        public void Cancel()
        {
            var result = _cliService.Shutdown("-a");
            ManageExecutionResponse(result);
        }
    }
}
