using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Threading;
using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Views;
using Microsoft.Win32;

namespace AxCopilot.Handlers;

public class SystemInfoHandler : IActionHandler
{
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
	private struct MEMORYSTATUSEX
	{
		public uint dwLength;

		public uint dwMemoryLoad;

		public ulong ullTotalPhys;

		public ulong ullAvailPhys;

		public ulong ullTotalPageFile;

		public ulong ullAvailPageFile;

		public ulong ullTotalVirtual;

		public ulong ullAvailVirtual;

		public ulong ullAvailExtendedVirtual;
	}

	internal sealed record InfoAction(string Type, string? Payload = null);

	private static volatile PerformanceCounter? _cpuCounter;

	private static float _cpuCached;

	private static DateTime _cpuUpdated;

	private static readonly object _cpuLock;

	public string? Prefix => "info";

	public PluginMetadata Metadata => new PluginMetadata("SystemInfo", "시스템 정보 — IP, 배터리, 볼륨, 가동시간 등", "1.0", "AX");

	[DllImport("winmm.dll")]
	private static extern int waveOutGetVolume(nint hwo, out uint dwVolume);

	[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
	[return: MarshalAs(UnmanagedType.Bool)]
	private static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);

	static SystemInfoHandler()
	{
		_cpuUpdated = DateTime.MinValue;
		_cpuLock = new object();
		Task.Run(delegate
		{
			try
			{
				PerformanceCounter performanceCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
				performanceCounter.NextValue();
				_cpuCounter = performanceCounter;
			}
			catch
			{
			}
		});
	}

	private static float GetCpuUsage()
	{
		try
		{
			PerformanceCounter cpuCounter = _cpuCounter;
			if (cpuCounter == null)
			{
				return -1f;
			}
			lock (_cpuLock)
			{
				if ((DateTime.Now - _cpuUpdated).TotalMilliseconds > 800.0)
				{
					_cpuCached = cpuCounter.NextValue();
					_cpuUpdated = DateTime.Now;
				}
				return _cpuCached;
			}
		}
		catch
		{
			return -1f;
		}
	}

	public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
	{
		string text = query.Trim().ToLowerInvariant();
		List<LauncherItem> list = new List<LauncherItem>();
		try
		{
			bool flag = string.IsNullOrEmpty(text);
			bool flag2 = flag || text.Contains("ip") || text.Contains("네트워크") || text.Contains("network");
			bool flag3 = flag || text.Contains("bat") || text.Contains("배터리") || text.Contains("battery");
			bool flag4 = flag || text.Contains("vol") || text.Contains("볼륨") || text.Contains("volume");
			bool flag5 = flag || text.Contains("up") || text.Contains("가동") || text.Contains("uptime");
			bool flag6 = flag || text.Contains("sys") || text.Contains("시스템") || text.Contains("system") || text.Contains("host") || text.Contains("호스트") || text.Contains("os");
			bool flag7 = flag || text.Contains("user") || text.Contains("사용자");
			bool flag8 = flag || text.Contains("cpu") || text.Contains("프로세서") || text.Contains("processor");
			bool flag9 = flag || text.Contains("ram") || text.Contains("메모리") || text.Contains("memory");
			bool flag10 = flag || text.Contains("disk") || text.Contains("디스크") || text.Contains("storage") || text.Contains("저장");
			bool flag11 = flag || text.Contains("screen") || text.Contains("화면") || text.Contains("resolution") || text.Contains("display");
			if (flag6)
			{
				list.Add(new LauncherItem("컴퓨터: " + Environment.MachineName, "OS: " + GetOsVersion() + "  ·  Enter로 시스템 정보 열기", null, new InfoAction("shell", "msinfo32"), null, "\ue7f4"));
			}
			if (flag7)
			{
				string text2 = Environment.UserDomainName + "\\" + Environment.UserName;
				list.Add(new LauncherItem("사용자: " + Environment.UserName, text2 + "  ·  Enter로 사용자 계정 설정 열기", null, new InfoAction("shell", "netplwiz"), null, "\ue77b"));
			}
			if (flag2)
			{
				string localIpAddress = GetLocalIpAddress();
				if (localIpAddress != null)
				{
					list.Add(new LauncherItem("로컬 IP: " + localIpAddress, "LAN / Wi-Fi 주소  ·  Enter로 네트워크 설정 열기", null, new InfoAction("ms_settings", "ms-settings:network"), null, "\ue968"));
				}
				string defaultGateway = GetDefaultGateway();
				if (defaultGateway != null)
				{
					list.Add(new LauncherItem("게이트웨이: " + defaultGateway, "기본 게이트웨이  ·  Enter로 네트워크 설정 열기", null, new InfoAction("ms_settings", "ms-settings:network"), null, "\ue968"));
				}
			}
			if (flag3)
			{
				LauncherItem batteryItem = GetBatteryItem();
				if (batteryItem != null)
				{
					list.Add(batteryItem);
				}
			}
			if (flag4)
			{
				LauncherItem volumeItem = GetVolumeItem();
				if (volumeItem != null)
				{
					list.Add(volumeItem);
				}
			}
			if (flag5)
			{
				TimeSpan timeSpan = TimeSpan.FromMilliseconds(Environment.TickCount64);
				string text3 = FormatUptime(timeSpan);
				DateTime value = DateTime.Now - timeSpan;
				list.Add(MakeItem("가동 시간: " + text3, $"마지막 재시작: {value:MM/dd HH:mm}", text3, "\ue823"));
			}
			if (flag8)
			{
				float cpuUsage = GetCpuUsage();
				string title = ((cpuUsage < 0f) ? "CPU: 측정 중…" : $"CPU: {(int)cpuUsage}%");
				string processorName = GetProcessorName();
				list.Add(new LauncherItem(title, (string.IsNullOrEmpty(processorName) ? "전체 CPU 사용률" : processorName) + "  ·  Enter로 리소스 모니터 열기", null, new InfoAction("resource_mon"), null, "\ue950"));
			}
			if (flag9)
			{
				MEMORYSTATUSEX lpBuffer = new MEMORYSTATUSEX
				{
					dwLength = (uint)Marshal.SizeOf<MEMORYSTATUSEX>()
				};
				if (GlobalMemoryStatusEx(ref lpBuffer))
				{
					double value2 = (double)lpBuffer.ullTotalPhys / 1024.0 / 1024.0 / 1024.0;
					double value3 = (double)(lpBuffer.ullTotalPhys - lpBuffer.ullAvailPhys) / 1024.0 / 1024.0 / 1024.0;
					uint dwMemoryLoad = lpBuffer.dwMemoryLoad;
					list.Add(new LauncherItem($"RAM: {value3:F1} / {value2:F1} GB  ({dwMemoryLoad}%)", $"사용 중: {value3:F1} GB  ·  여유: {(double)lpBuffer.ullAvailPhys / 1024.0 / 1024.0 / 1024.0:F1} GB  ·  Enter로 리소스 모니터 열기", null, new InfoAction("resource_mon"), null, "\ue950"));
				}
			}
			if (flag10)
			{
				foreach (DriveInfo item in from d in DriveInfo.GetDrives()
					where d.IsReady && d.DriveType == DriveType.Fixed
					select d)
				{
					double num = (double)item.TotalSize / 1024.0 / 1024.0 / 1024.0;
					double num2 = (double)item.AvailableFreeSpace / 1024.0 / 1024.0 / 1024.0;
					double num3 = num - num2;
					int value4 = (int)(num3 / num * 100.0);
					string value5 = (string.IsNullOrWhiteSpace(item.VolumeLabel) ? item.Name.TrimEnd('\\') : item.VolumeLabel);
					list.Add(new LauncherItem($"드라이브 {item.Name.TrimEnd('\\')}  ({value5})  — {num3:F0} / {num:F0} GB  ({value4}%)", $"여유 공간: {num2:F1} GB  ·  Enter로 탐색기 열기", null, new InfoAction("open_drive", item.RootDirectory.FullName), null, "\ueda2"));
				}
			}
			if (flag11)
			{
				double primaryScreenWidth = SystemParameters.PrimaryScreenWidth;
				double primaryScreenHeight = SystemParameters.PrimaryScreenHeight;
				list.Add(new LauncherItem($"화면: {(int)primaryScreenWidth} × {(int)primaryScreenHeight}", "기본 모니터 해상도  ·  Enter로 디스플레이 설정 열기", null, new InfoAction("ms_settings", "ms-settings:display"), null, "\ue7f4"));
			}
		}
		catch (Exception ex)
		{
			LogService.Warn("시스템 정보 조회 오류: " + ex.Message);
			list.Add(new LauncherItem("시스템 정보 조회 실패", ex.Message, null, null, null, "\uea39"));
		}
		if (list.Count == 0)
		{
			list.Add(new LauncherItem("시스템 정보 없음", "ip · battery · volume · uptime · system 키워드로 검색하세요", null, null, null, "\ue946"));
		}
		return Task.FromResult((IEnumerable<LauncherItem>)list);
	}

	public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
	{
		object data = item.Data;
		InfoAction action = data as InfoAction;
		if ((object)action == null)
		{
			return Task.CompletedTask;
		}
		switch (action.Type)
		{
		case "copy":
			if (string.IsNullOrWhiteSpace(action.Payload))
			{
				break;
			}
			try
			{
				((DispatcherObject)System.Windows.Application.Current).Dispatcher.Invoke((Action)delegate
				{
					System.Windows.Clipboard.SetText(action.Payload);
				});
				LogService.Info("클립보드 복사: " + action.Payload);
			}
			catch (Exception ex2)
			{
				LogService.Warn("클립보드 복사 실패: " + ex2.Message);
			}
			break;
		case "open_drive":
			if (!string.IsNullOrWhiteSpace(action.Payload))
			{
				try
				{
					Process.Start(new ProcessStartInfo("explorer.exe", action.Payload)
					{
						UseShellExecute = true
					});
				}
				catch (Exception ex4)
				{
					LogService.Warn("드라이브 열기 실패: " + ex4.Message);
				}
			}
			break;
		case "resource_mon":
			((DispatcherObject)System.Windows.Application.Current).Dispatcher.Invoke((Action)delegate
			{
				ResourceMonitorWindow resourceMonitorWindow = System.Windows.Application.Current.Windows.OfType<ResourceMonitorWindow>().FirstOrDefault();
				if (resourceMonitorWindow != null)
				{
					resourceMonitorWindow.Activate();
				}
				else
				{
					new ResourceMonitorWindow().Show();
				}
			});
			break;
		case "shell":
			if (!string.IsNullOrWhiteSpace(action.Payload))
			{
				try
				{
					Process.Start(new ProcessStartInfo(action.Payload)
					{
						UseShellExecute = true
					});
				}
				catch (Exception ex3)
				{
					LogService.Warn("셸 명령 실행 실패: " + ex3.Message);
				}
			}
			break;
		case "ms_settings":
			if (!string.IsNullOrWhiteSpace(action.Payload))
			{
				try
				{
					Process.Start(new ProcessStartInfo(action.Payload)
					{
						UseShellExecute = true
					});
				}
				catch (Exception ex)
				{
					LogService.Warn("설정 열기 실패: " + ex.Message);
				}
			}
			break;
		}
		return Task.CompletedTask;
	}

	private static LauncherItem MakeItem(string title, string subtitle, string? copyValue, string symbol)
	{
		return new LauncherItem(title, subtitle, null, (copyValue != null) ? new InfoAction("copy", copyValue) : null, null, symbol);
	}

	private static string? GetLocalIpAddress()
	{
		try
		{
			NetworkInterface[] allNetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
			foreach (NetworkInterface networkInterface in allNetworkInterfaces)
			{
				if (networkInterface.OperationalStatus != OperationalStatus.Up)
				{
					continue;
				}
				NetworkInterfaceType networkInterfaceType = networkInterface.NetworkInterfaceType;
				if ((networkInterfaceType == NetworkInterfaceType.Loopback || networkInterfaceType == NetworkInterfaceType.Tunnel) ? true : false)
				{
					continue;
				}
				foreach (UnicastIPAddressInformation unicastAddress in networkInterface.GetIPProperties().UnicastAddresses)
				{
					if (unicastAddress.Address.AddressFamily == AddressFamily.InterNetwork)
					{
						return unicastAddress.Address.ToString();
					}
				}
			}
		}
		catch
		{
		}
		return null;
	}

	private static string? GetDefaultGateway()
	{
		try
		{
			NetworkInterface[] allNetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
			foreach (NetworkInterface networkInterface in allNetworkInterfaces)
			{
				if (networkInterface.OperationalStatus == OperationalStatus.Up)
				{
					GatewayIPAddressInformation gatewayIPAddressInformation = networkInterface.GetIPProperties().GatewayAddresses.FirstOrDefault((GatewayIPAddressInformation g) => g.Address.AddressFamily == AddressFamily.InterNetwork);
					if (gatewayIPAddressInformation != null)
					{
						return gatewayIPAddressInformation.Address.ToString();
					}
				}
			}
		}
		catch
		{
		}
		return null;
	}

	private static LauncherItem? GetBatteryItem()
	{
		try
		{
			PowerStatus powerStatus = SystemInformation.PowerStatus;
			float batteryLifePercent = powerStatus.BatteryLifePercent;
			if (batteryLifePercent < 0f)
			{
				return new LauncherItem("배터리: 해당 없음", "데스크톱 PC 또는 항상 연결됨  ·  Enter로 전원 설정 열기", null, new InfoAction("ms_settings", "ms-settings:powersleep"), null, "\ue83f");
			}
			int num = (int)(batteryLifePercent * 100f);
			bool flag = powerStatus.PowerLineStatus == System.Windows.Forms.PowerLineStatus.Online;
			string text = ((powerStatus.BatteryLifeRemaining >= 0) ? ("  ·  잔여: " + FormatUptime(TimeSpan.FromSeconds(powerStatus.BatteryLifeRemaining))) : "");
			string symbol = (flag ? "\ue83e" : ((num > 50) ? "\ue83f" : "\ueba0"));
			return new LauncherItem($"배터리: {num}%{(flag ? "  ⚡ 충전 중" : "")}", "전원: " + (flag ? "AC 연결됨" : "배터리 사용 중") + text + "  ·  Enter로 전원 설정 열기", null, new InfoAction("ms_settings", "ms-settings:powersleep"), null, symbol);
		}
		catch
		{
			return null;
		}
	}

	private static LauncherItem? GetVolumeItem()
	{
		try
		{
			if (waveOutGetVolume(IntPtr.Zero, out var dwVolume) == 0)
			{
				int num = (int)((double)(dwVolume & 0xFFFF) / 655.35);
				int num2 = (int)((double)((dwVolume >> 16) & 0xFFFF) / 655.35);
				int num3 = (num + num2) / 2;
				return new LauncherItem($"볼륨: {num3}%", $"L: {num}%  ·  R: {num2}%  ·  Enter로 사운드 설정 열기", null, new InfoAction("ms_settings", "ms-settings:sound"), null, (num3 == 0) ? "\ue74f" : "\ue995");
			}
		}
		catch
		{
		}
		return null;
	}

	private static string GetOsVersion()
	{
		try
		{
			using RegistryKey registryKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion");
			if (registryKey != null)
			{
				string text = (registryKey.GetValue("ProductName") as string) ?? "Windows";
				string text2 = (registryKey.GetValue("CurrentBuildNumber") as string) ?? "";
				object value = registryKey.GetValue("UBR");
				return (value != null) ? $"{text} (빌드 {text2}.{value})" : (text + " (빌드 " + text2 + ")");
			}
		}
		catch
		{
		}
		return Environment.OSVersion.ToString();
	}

	private static string GetProcessorName()
	{
		try
		{
			using RegistryKey registryKey = Registry.LocalMachine.OpenSubKey("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0");
			return (registryKey?.GetValue("ProcessorNameString") as string) ?? "";
		}
		catch
		{
			return "";
		}
	}

	private static string FormatUptime(TimeSpan t)
	{
		if (!(t.TotalDays >= 1.0))
		{
			if (!(t.TotalHours >= 1.0))
			{
				return $"{t.Minutes}분 {t.Seconds}초";
			}
			return $"{t.Hours}시간 {t.Minutes}분";
		}
		return $"{(int)t.TotalDays}일 {t.Hours}시간 {t.Minutes}분";
	}
}
