using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Net.NetworkInformation;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using Microsoft.WindowsAPICodePack.Shell;
using Microsoft.WindowsAPICodePack.Shell.PropertySystem;
using NetFwTypeLib;
using Valg.EVA.Skanning.Configuration;

namespace Valg.EVA.Skanning.Services.Security
{
	public class SecurityComplianceScanService
	{
		private readonly string[] _knownPasswords = new[] { "Valg2017", "Valg2019", "Valg2021" };
		private readonly string[] _hostDestinationsToPing = new[] { "vg.no", "db.no", "valg.no" };
		public event SecurityComplianceScan SecurityComplianceScanDone;
		public delegate void SecurityComplianceScan(SecurityComplianceResult result);
		public void Scan()
		{
			var result = new SecurityComplianceResult()
			{
				IsFirewallEnabled = IsWindowsFirewallEnabled(),
				IsInternetAvailable = IsInternetAvailable(),
				IsUserAdministrator = IsAdministrator(),
				IsKnownPasswordUsed = IsUsingKnownPasswords(),
				IsConnectedWithWifi = IsConnectedWithWifi,
				IsConnectedWithBluetooth = IsConnectedWithBluetooth,
				IsBitLockerActivated = IsBitLockerActivated(),
                IsDatabasePermissionSetRestricted = IsDatabasePermissionSetRestricted()
			};
			SecurityComplianceScanDone?.Invoke(result);
		}
		public bool IsConnectedWithBluetooth => NetworkInterface.GetAllNetworkInterfaces().Any(p => p.Name.ToLower().Contains("bluetooth") && p.OperationalStatus == OperationalStatus.Up);
		public bool IsConnectedWithWifi => NetworkInterface.GetAllNetworkInterfaces()
			.Any(nic => nic.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 && nic.OperationalStatus == OperationalStatus.Up);

	    private bool IsDatabasePermissionSetRestricted()
	    {
	        var applicationConfigurationReader = new ApplicationConfigurationReader(new DefaultConfigurationFileProvider());
	        using (var cnn = new SqlConnection(applicationConfigurationReader.GetConnectionString()))
	        {
                cnn.Open();
	            using (var cmd = cnn.CreateCommand())
	            {
	                cmd.CommandText = "select count(permission_name) from fn_my_permissions(NULL, 'DATABASE')" +
	                                  " where permission_name not in" +
	                                  " ('CONNECT', 'EXECUTE', 'VIEW ANY COLUMN ENCRYPTION KEY DEFINITION', 'VIEW ANY COLUMN MASTER KEY DEFINITION')";
	                var result = Convert.ToDecimal(cmd.ExecuteScalar());
	                if (result > 0)
	                {
	                    return false;
	                }
	            }
	            using (var cmd = cnn.CreateCommand())
	            {
	                cmd.CommandText = "select count(permission_name) from fn_my_permissions(NULL, 'SERVER')" +
	                                  " where permission_name not in" +
	                                  " ('CONNECT SQL', 'VIEW ANY DATABASE')";
	                var result = Convert.ToDecimal(cmd.ExecuteScalar());
	                if (result > 0)
	                {
	                    return false;
	                }
	            }
	        }
	        return true;
	    }

		private bool IsBitLockerActivated()
		{
			IShellProperty prop = ShellObject.FromParsingName("C:").Properties.GetProperty("System.Volume.BitLockerProtection");
			int? bitLockerProtectionStatus = (prop as ShellProperty<int?>)?.Value;

			if (bitLockerProtectionStatus.HasValue && (bitLockerProtectionStatus == 1 || bitLockerProtectionStatus == 3 || bitLockerProtectionStatus == 5))
			{
				return true;
			}
			return false;
		}

		private bool IsUsingKnownPasswords()
		{
			foreach (var password in _knownPasswords)
			{
				try
				{
					using (Impersonation.LogonUser(Environment.UserDomainName, Environment.UserName, password, LogonType.Interactive))
					{
						return true;
					}
				}
				catch (Exception)
				{
				}
			}
			return false;
		}

		private bool IsAdministrator()
		{
			var identity = WindowsIdentity.GetCurrent();
			var principal = new WindowsPrincipal(identity);
			return principal.IsInRole(WindowsBuiltInRole.Administrator);
		}

		private bool IsWindowsFirewallEnabled()
		{
			var NetFwMgrType = Type.GetTypeFromProgID("HNetCfg.FwMgr", false);
		    if (NetFwMgrType == null)
		    {
		        return false;
		    }
			var firewallManager = (INetFwMgr)Activator.CreateInstance(NetFwMgrType);
			if (firewallManager.LocalPolicy.CurrentProfile.FirewallEnabled)
			{
				return true;
			}

			return false;
		}

		private bool IsInternetAvailable()
		{
		    var result = false;
		    Parallel.ForEach(_hostDestinationsToPing, (destination, state) =>
		    {
		        var reply = Ping(destination);
		        if (reply)
		        {
		            result = true;
                    state.Break();
		        }
            });
			return result;
		}

		private bool Ping(string destination)
		{
			var ping = new Ping();
			try
            {
                var reply = ping.Send(destination);
                return reply?.Status == IPStatus.Success;
            }
			catch (Exception)
			{
				return false;
			}
		}

	}
}

