using NetworkResurrector.Server.Abstractions;
using System.Globalization;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace NetworkResurrector.WakeOnLan.Inhouse
{
    internal class WolDriver : IWakeOnLanService
    {
        private readonly WolClient _client;

        public WolDriver(WolClient client)
        {
            _client = client;
        }

        public async Task<(bool success, string message)> Wake(string macAddress)
        {
            //remove all non 0-9, A-F, a-f characters 
            macAddress = Regex.Replace(macAddress, @"[^0-9A-Fa-f]", "");

            //check if mac adress length is valid
            if (macAddress.Length != 12)
                return (false, "Invalid MAC address.");
            else
                return await Wakeup(macAddress);
        }

        #region Wakeup
        /// <summary>
        /// Wakes up the machine with the given <paramref name="macAddress"/>.
        /// </summary>
        /// <remarks>
        /// <para>
        /// <note>
        /// <list type="number">
        /// <item> The motherboard must support Wake On LAN.</item>
        /// <item> The NIC must support Wake On LAN.</item>
        /// <item> There must be a wire connecting the motherboard's WOL port to
        /// the NIC's WOL port. Usually there always is a connection on most of
        /// the PCs.</item>
        /// <item> The Wake On LAN feature must be enabled in the motherboard's
        /// BIOS. Usually this is also enabled by default, but you might like to
        /// check again.</item>
        /// <item> The "Good Connection" light on the back of the NIC must be lit
        /// when the machine is off. (By default always good if you are not
        /// facing any network issues)</item>
        /// <item> Port 12287 (0x2FFF) must be open. (By default it should be
        /// open unless some antivirus or any other such program has changed 
        /// settings.)</item>
        /// <item> Packets cannot be broadcast across the Internet.  That's why
        /// it's called Wake On Lan, not Wake On Internet.</item>
        /// <item> To find your MAC address, run the MSINFO32.EXE tool that is a
        /// part of Windows and navigate to Components > Network > Adapter
        /// or simply type nbtstat -a &lt;your hostname &lt at command prompt.
        /// e.g. nbtstat -a mymachinename or nbtstat -A 10.2.100.213.
        /// <param name="macAddress">The MAC address of the host which has to be
        /// woken up.</param>
        /// 
        private async Task<(bool success, string message)> Wakeup(string macAddress)
        {
            _client.Connect(new IPAddress(0xffffffff) /*255.255.255.255  i.e broadcast*/, 0x2fff /*port = 12287*/);

            if (!_client.SetClientInBrodcastMode())
                return (false, "Remote client could not be set in broadcast mode!");

            int byteCount = 0;
            byte[] bytes = new byte[102];

            for (int trailer = 0; trailer < 6; trailer++)
            {
                bytes[byteCount++] = 0xFF;
            }

            for (int macPackets = 0; macPackets < 16; macPackets++)
            {
                int i = 0;
                for (int macBytes = 0; macBytes < 6; macBytes++)
                {
                    bytes[byteCount++] = byte.Parse(macAddress.Substring(i, 2), NumberStyles.HexNumber);
                    i += 2;
                }
            }

            int returnValue = await _client.SendAsync(bytes, byteCount);

            return (true, $"{returnValue} bytes sent to {macAddress}");
        }
        #endregion
    }
}
