using System.Diagnostics;
using System.Management;

using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;

namespace Kit.Helpers
{
    public class OperatingSystemInfo
    {
        public string OSVersion { get; set; } = string.Empty;
        public string BitOperatingSystem { get; set; } = string.Empty;
        public string BitProcess { get; set; } = string.Empty;
    }

    public interface IHardwareInfoProvider
    {
        string GetProcessorId();
        string GetBoardSerial();
        string GetMacAddress();
        string GetMachineName();
    }

    internal abstract class HardwareInfoProviderBase : IHardwareInfoProvider
    {
        public abstract string GetProcessorId();
        public abstract string GetBoardSerial();
        public string GetMacAddress()
        {
            try
            {
                var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces()
                    .Where(n => n.OperationalStatus == OperationalStatus.Up && n.NetworkInterfaceType != NetworkInterfaceType.Loopback)
                    .FirstOrDefault();

                if (networkInterfaces != null)
                {
                    return networkInterfaces.GetPhysicalAddress().ToString();
                }
                return "N/A";
            }
            catch (Exception ex)
            {
                return $"Error: {ex.Message}";
            }
        }

        public string GetMachineName() => Environment.MachineName;
    }

#pragma warning disable CA1416 // Validate platform compatibility
    internal class HardwareInfoProviderWindows : HardwareInfoProviderBase, IHardwareInfoProvider
    {
        private static string _scope = "root\\CIMV2";
        private static string GetComponent(string scope, string hwClass, string syntax)
        {
            ManagementObjectSearcher mos = new ManagementObjectSearcher(scope, "SELECT * FROM " + hwClass);

            string result = "";

            foreach (ManagementObject mObj in mos.Get())
            {
                result = Convert.ToString(mObj[syntax]) ?? string.Empty;
            }

            return result;
        }

        public override string GetProcessorId() => GetComponent(_scope, "Win32_processor", "ProcessorID");
        public override string GetBoardSerial() => GetComponent(_scope, "Win32_BaseBoard", "SerialNumber");
    }

    internal class HardwareInfoProviderLinux : HardwareInfoProviderBase, IHardwareInfoProvider
    {
        private string ParseCpuIdOutput(string output)
        {
            // Пример парсинга вывода cpuid
            // Ищем сигнатуру процессора (eax=1)
            var lines = output.Split('\n');
            foreach (var line in lines)
            {
                if (line.Contains("0x00000001 0x00:"))
                {
                    // Пример строки: "0x00000001 0x00: eax=0x000306c3 ebx=0x01000800 ecx=0x7ffafbff edx=0xbfebfbff"
                    var parts = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
                    string eax = parts[2].Split('=')[1]; // Например, "0x000306c3"
                    string ebx = parts[3].Split('=')[1]; // Например, "0x01000800"
                    string edx = parts[5].Split('=')[1]; // Например, "0xbfebfbff"

                    // Комбинируем как уникальный идентификатор
                    //return $"{eax}-{ebx}-{edx}";
                    return $"{edx.Split('x').ElementAt(1)}{eax.Split('x').ElementAt(1)}".ToUpper();
                }
            }

            return "Не удалось найти данные CPUID";
        }
        public override string GetProcessorId()
        {
            try
            {
                // Настройка процесса для вызова cpuid
                var process = new Process
                {
                    StartInfo = new ProcessStartInfo
                    {
                        FileName = "cpuid",
                        Arguments = "-r", // Сырой вывод CPUID
                        RedirectStandardOutput = true,
                        UseShellExecute = false,
                        CreateNoWindow = true
                    }
                };

                // Запуск процесса
                process.Start();
                string output = process.StandardOutput.ReadToEnd();
                process.WaitForExit();

                // Парсинг вывода для получения нужной информации
                return ParseCpuIdOutput(output);
            }
            catch (Exception ex)
            {
                return $"Ошибка при получении Hardware ID: {ex.Message}";
            }
        }
        public override string GetBoardSerial() => string.Empty;
    }

    internal class HardwareInfoProviderDebug : HardwareInfoProviderBase, IHardwareInfoProvider
    {
        public override string GetProcessorId() => "FEDCBA9876543210";
        public override string GetBoardSerial() => "Debug board serial number";
    }
#pragma warning restore CA1416 // Validate platform compatibility

    public interface IHardwareInfoService
    {
        IHardwareInfoProvider Provider { get; }
        OperatingSystemInfo GetOperatingSystemInfo();
        string GetHardwareId();
    }

    internal class HardwareInfoService : IHardwareInfoService
    {
        public OperatingSystemInfo GetOperatingSystemInfo() => new OperatingSystemInfo
        {
            BitOperatingSystem = Environment.Is64BitProcess ? "x64" : "x32",
            BitProcess = Environment.Is64BitOperatingSystem ? "x64" : "x32",
            OSVersion = RuntimeInformation.OSDescription
        };

        public IHardwareInfoProvider Provider { get; private set; }
        public HardwareInfoService(IHardwareInfoProvider infoProvider)
        {
            Provider = infoProvider;
        }

        public string GetHardwareId()
        {
            string processorId = Provider.GetProcessorId();
            string baseBoardId = Provider.GetBoardSerial();
            string macAddress = Provider.GetMacAddress();
            string machineName = Provider.GetMachineName();

            return CalculateHash($"{processorId}{baseBoardId}{macAddress}{machineName}");
        }

        private string CalculateHash(string input)
        {
            using (var algorithm = SHA512.Create())
            {
                var hashedBytes = algorithm.ComputeHash(Encoding.UTF8.GetBytes(input));
                return BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
            }
        }
    }
}
