using LibreHardwareMonitor.Hardware;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;

namespace HardwareAgent
{
    public static class HardwareReader
    {
        private static Computer computer;

        static HardwareReader()
        {
            computer = new Computer
            {
                IsCpuEnabled = true,
                IsGpuEnabled = true,
                IsMotherboardEnabled = true
            };
            computer.Open();
        }

        public static object CollectAll()
        {
            return new
            {
                basic = GetBasicInfo(),
                cpu = GetCpu(),
                ram = GetRam(),
                disk = GetDisk(),
                sensors = GetSensors()
            };
        }

        static object GetBasicInfo()
        {
            return new
            {
                hostname = Environment.MachineName,
                os = Environment.OSVersion.ToString(),
                time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
            };
        }

        static object GetCpu()
        {
            var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
            cpuCounter.NextValue();
            System.Threading.Thread.Sleep(500);

            return new
            {
                usage_percent = Math.Round(cpuCounter.NextValue(), 2),
                core_count = Environment.ProcessorCount
            };
        }

        static object GetRam()
        {
            var ramCounter = new PerformanceCounter("Memory", "Available MBytes");
            float available = ramCounter.NextValue();

            float total = GetTotalRamMb();
            float used = total - available;

            return new
            {
                total_gb = Math.Round(total / 1024, 2),
                used_gb = Math.Round(used / 1024, 2),
                percent = Math.Round((used / total) * 100, 2)
            };
        }

        static float GetTotalRamMb()
        {
            var searcher = new System.Management.ManagementObjectSearcher(
                "SELECT TotalPhysicalMemory FROM Win32_ComputerSystem");

            foreach (var item in searcher.Get())
                return Convert.ToSingle(item["TotalPhysicalMemory"]) / 1024 / 1024;

            return 0;
        }

        static List<object> GetDisk()
        {
            var list = new List<object>();

            foreach (var drive in DriveInfo.GetDrives())
            {
                if (!drive.IsReady) continue;

                list.Add(new
                {
                    device = drive.Name,
                    total_gb = Math.Round(drive.TotalSize / 1e9, 2),
                    used_gb = Math.Round((drive.TotalSize - drive.AvailableFreeSpace) / 1e9, 2),
                    percent = Math.Round(
                        ((double)(drive.TotalSize - drive.AvailableFreeSpace) / drive.TotalSize) * 100, 2)
                });
            }
            return list;
        }

        static object GetSensors()
        {
            var cpuTemp = new List<object>();
            var gpuTemp = new List<object>();
            var fan = new List<object>();

            foreach (var hardware in computer.Hardware)
            {
                hardware.Update();

                foreach (var sensor in hardware.Sensors)
                {
                    if (sensor.SensorType == SensorType.Temperature && sensor.Value.HasValue)
                    {
                        if (hardware.HardwareType == HardwareType.Cpu)
                            cpuTemp.Add(new { name = sensor.Name, value = sensor.Value });

                        if (hardware.HardwareType == HardwareType.GpuNvidia ||
                            hardware.HardwareType == HardwareType.GpuAmd)
                            gpuTemp.Add(new { name = sensor.Name, value = sensor.Value });
                    }

                    if (sensor.SensorType == SensorType.Fan && sensor.Value.HasValue)
                    {
                        fan.Add(new { name = sensor.Name, rpm = sensor.Value });
                    }
                }
            }

            return new
            {
                cpu_temp = cpuTemp,
                gpu_temp = gpuTemp,
                fan = fan
            };
        }
    }
}
