using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AxCopilot.SDK;
using AxCopilot.Services;
using Microsoft.Win32;

namespace AxCopilot.Handlers;

public class UninstallHandler : IActionHandler
{
	private static readonly string[] _regPaths = new string[2] { "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall", "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall" };

	private static (DateTime At, List<InstalledApp> Apps)? _cache;

	private static readonly TimeSpan CacheTtl = TimeSpan.FromSeconds(30.0);

	public string? Prefix => "uninstall";

	public PluginMetadata Metadata => new PluginMetadata("Uninstall", "앱 제거 — uninstall 뒤에 앱 이름 입력", "1.0", "AX");

	public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
	{
		string q = query.Trim();
		if (string.IsNullOrWhiteSpace(q))
		{
			return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("제거할 앱 이름을 입력하세요", "예: uninstall chrome  ·  uninstall office", null, null, null, "\ue74d")));
		}
		List<InstalledApp> installedApps = GetInstalledApps();
		List<InstalledApp> source = (from a in installedApps
			where a.Name.Contains(q, StringComparison.OrdinalIgnoreCase) || (a.Publisher?.Contains(q, StringComparison.OrdinalIgnoreCase) ?? false)
			orderby a.Name
			select a).Take(12).ToList();
		if (!source.Any())
		{
			return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("검색 결과 없음", "'" + q + "'에 해당하는 설치된 앱이 없습니다", null, null, null, "\ue946")));
		}
		List<LauncherItem> result = source.Select((InstalledApp a) => new LauncherItem(a.Name, BuildSubtitle(a), null, a, null, "\ue74d")).ToList();
		return Task.FromResult((IEnumerable<LauncherItem>)result);
	}

	public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
	{
		if (!(item.Data is InstalledApp installedApp))
		{
			return Task.CompletedTask;
		}
		if (string.IsNullOrWhiteSpace(installedApp.UninstallString))
		{
			LogService.Warn("제거 문자열 없음: " + installedApp.Name);
			return Task.CompletedTask;
		}
		try
		{
			string text = installedApp.UninstallString.Trim();
			if (text.StartsWith("msiexec", StringComparison.OrdinalIgnoreCase))
			{
				string arguments = text.Substring("msiexec".Length).Trim();
				Process.Start(new ProcessStartInfo("msiexec.exe", arguments)
				{
					UseShellExecute = true
				});
			}
			else
			{
				string fileName;
				string arguments2;
				if (text.StartsWith('"'))
				{
					int num = text.IndexOf('"', 1);
					fileName = ((num > 0) ? text.Substring(1, num - 1) : text);
					object obj;
					if (num <= 0)
					{
						obj = "";
					}
					else
					{
						string text2 = text;
						int num2 = num + 1;
						obj = text2.Substring(num2, text2.Length - num2).Trim();
					}
					arguments2 = (string)obj;
				}
				else
				{
					int num3 = text.IndexOf(' ');
					if (num3 > 0)
					{
						fileName = text.Substring(0, num3);
						string text2 = text;
						int num2 = num3 + 1;
						arguments2 = text2.Substring(num2, text2.Length - num2);
					}
					else
					{
						fileName = text;
						arguments2 = "";
					}
				}
				ProcessStartInfo startInfo = new ProcessStartInfo(fileName, arguments2)
				{
					UseShellExecute = true
				};
				Process.Start(startInfo);
			}
		}
		catch (Exception ex)
		{
			LogService.Warn("제거 실행 실패 [" + installedApp.Name + "]: " + ex.Message);
		}
		return Task.CompletedTask;
	}

	private static string BuildSubtitle(InstalledApp a)
	{
		List<string> list = new List<string>();
		if (!string.IsNullOrWhiteSpace(a.Publisher))
		{
			list.Add(a.Publisher);
		}
		if (!string.IsNullOrWhiteSpace(a.Version))
		{
			list.Add("v" + a.Version);
		}
		if (!string.IsNullOrWhiteSpace(a.InstallDate))
		{
			list.Add(a.InstallDate);
		}
		list.Add("Enter로 제거");
		return string.Join("  ·  ", list);
	}

	private static List<InstalledApp> GetInstalledApps()
	{
		if (_cache.HasValue && DateTime.Now - _cache.Value.At < CacheTtl)
		{
			return _cache.Value.Apps;
		}
		List<InstalledApp> list = new List<InstalledApp>();
		HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
		RegistryKey[] array = new RegistryKey[2]
		{
			Registry.LocalMachine,
			Registry.CurrentUser
		};
		foreach (RegistryKey registryKey in array)
		{
			string[] regPaths = _regPaths;
			foreach (string name in regPaths)
			{
				try
				{
					using RegistryKey registryKey2 = registryKey.OpenSubKey(name);
					if (registryKey2 == null)
					{
						continue;
					}
					string[] subKeyNames = registryKey2.GetSubKeyNames();
					foreach (string name2 in subKeyNames)
					{
						try
						{
							using RegistryKey registryKey3 = registryKey2.OpenSubKey(name2);
							if (registryKey3 != null)
							{
								string text = registryKey3.GetValue("DisplayName") as string;
								string text2 = registryKey3.GetValue("UninstallString") as string;
								if (!string.IsNullOrWhiteSpace(text) && !string.IsNullOrWhiteSpace(text2) && (!text.StartsWith("KB", StringComparison.OrdinalIgnoreCase) || text.Length >= 12) && hashSet.Add(text) && (!(registryKey3.GetValue("SystemComponent") is int num) || num != 1))
								{
									list.Add(new InstalledApp
									{
										Name = text,
										UninstallString = text2,
										Publisher = (registryKey3.GetValue("Publisher") as string),
										Version = (registryKey3.GetValue("DisplayVersion") as string),
										InstallDate = FormatDate(registryKey3.GetValue("InstallDate") as string)
									});
								}
							}
						}
						catch
						{
						}
					}
				}
				catch
				{
				}
			}
		}
		list.Sort((InstalledApp a, InstalledApp b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase));
		_cache = (DateTime.Now, list);
		return list;
	}

	private static string? FormatDate(string? raw)
	{
		if (raw != null && raw.Length == 8 && int.TryParse(raw, out var _))
		{
			return $"{raw.Substring(0, 4)}-{raw.Substring(4, 2)}-{raw.Substring(6, 2)}";
		}
		return null;
	}
}
