using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.NetworkInformation;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using AxCopilot.SDK;
using AxCopilot.Services;

namespace AxCopilot.Handlers;

public class PortHandler : IActionHandler
{
	private static readonly Dictionary<int, string> _procCache = new Dictionary<int, string>();

	private static readonly Dictionary<int, int> _pidMap = new Dictionary<int, int>();

	private static DateTime _cacheExpiry = DateTime.MinValue;

	public string? Prefix => "port";

	public PluginMetadata Metadata => new PluginMetadata("PortChecker", "포트 & 프로세스 점검 — port 뒤에 포트번호 또는 프로세스명", "1.0", "AX");

	public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
	{
		RefreshProcessCache();
		TcpConnectionInformation[] activeTcpConnections;
		try
		{
			IPGlobalProperties iPGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
			activeTcpConnections = iPGlobalProperties.GetActiveTcpConnections();
		}
		catch (Exception ex)
		{
			LogService.Warn("포트 조회 실패: " + ex.Message);
			return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("네트워크 정보를 가져올 수 없습니다", ex.Message, null, null, null, "\ue7ba")));
		}
		string text = query.Trim();
		if (string.IsNullOrWhiteSpace(text))
		{
			List<LauncherItem> list = (from c in activeTcpConnections
				where c.State == TcpState.Established || c.State == TcpState.Listen
				orderby c.LocalEndPoint.Port
				select c).Take(20).Select(delegate(TcpConnectionInformation c)
			{
				string processNameForPort = GetProcessNameForPort(c.LocalEndPoint.Port);
				string text2 = ((c.State == TcpState.Listen) ? "LISTEN" : "ESTABLISHED");
				return new LauncherItem($":{c.LocalEndPoint.Port}  →  {c.RemoteEndPoint}", text2 + "  ·  " + processNameForPort + "  ·  Enter로 포트번호 복사", null, c.LocalEndPoint.Port.ToString(), null, "\ue968");
			}).ToList();
			if (!list.Any())
			{
				list.Add(new LauncherItem("활성 연결 없음", "TCP 연결이 감지되지 않았습니다", null, null, null, "\ue968"));
			}
			return Task.FromResult((IEnumerable<LauncherItem>)list);
		}
		if (int.TryParse(text, out var portNum))
		{
			List<TcpConnectionInformation> source = activeTcpConnections.Where((TcpConnectionInformation c) => c.LocalEndPoint.Port == portNum || c.RemoteEndPoint.Port == portNum).ToList();
			if (!source.Any())
			{
				return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem($"포트 {portNum} — 사용 중 아님", "해당 포트를 사용하는 TCP 연결이 없습니다", null, portNum.ToString(), null, "\ue946")));
			}
			List<LauncherItem> result = source.Select(delegate(TcpConnectionInformation c)
			{
				string processNameForPort = GetProcessNameForPort(c.LocalEndPoint.Port);
				int pidForPort = GetPidForPort(c.LocalEndPoint.Port);
				return new LauncherItem($":{c.LocalEndPoint.Port}  ←→  {c.RemoteEndPoint}", $"{c.State}  ·  {processNameForPort} (PID {pidForPort})  ·  Enter로 PID 복사", null, (pidForPort > 0) ? pidForPort.ToString() : portNum.ToString(), null, "\ue968");
			}).ToList();
			return Task.FromResult((IEnumerable<LauncherItem>)result);
		}
		string procLower = text.ToLowerInvariant();
		List<LauncherItem> list2 = activeTcpConnections.Where(delegate(TcpConnectionInformation c)
		{
			string text2 = GetProcessNameForPort(c.LocalEndPoint.Port).ToLowerInvariant();
			return text2.Contains(procLower);
		}).Take(15).Select(delegate(TcpConnectionInformation c)
		{
			string processNameForPort = GetProcessNameForPort(c.LocalEndPoint.Port);
			return new LauncherItem($"{processNameForPort}  :  {c.LocalEndPoint.Port}  →  {c.RemoteEndPoint}", $"{c.State}  ·  Enter로 포트번호 복사", null, c.LocalEndPoint.Port.ToString(), null, "\ue968");
		})
			.ToList();
		if (!list2.Any())
		{
			list2.Add(new LauncherItem("'" + text + "' — 연결 없음", "해당 프로세스의 TCP 연결이 없습니다", null, null, null, "\ue7ba"));
		}
		return Task.FromResult((IEnumerable<LauncherItem>)list2);
	}

	public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
	{
		if (item.Data is string text)
		{
			try
			{
				Clipboard.SetText(text);
			}
			catch
			{
			}
		}
		return Task.CompletedTask;
	}

	private static void RefreshProcessCache()
	{
		if (DateTime.Now < _cacheExpiry)
		{
			return;
		}
		_procCache.Clear();
		_pidMap.Clear();
		try
		{
			Process[] processes = Process.GetProcesses();
			foreach (Process process in processes)
			{
				try
				{
					_procCache[process.Id] = process.ProcessName;
				}
				catch
				{
				}
			}
		}
		catch (Exception ex)
		{
			LogService.Warn("프로세스 목록 갱신 실패: " + ex.Message);
		}
		try
		{
			ProcessStartInfo startInfo = new ProcessStartInfo("netstat", "-ano")
			{
				RedirectStandardOutput = true,
				UseShellExecute = false,
				CreateNoWindow = true
			};
			using Process process2 = Process.Start(startInfo);
			if (process2 != null)
			{
				string text = process2.StandardOutput.ReadToEnd();
				process2.WaitForExit(2000);
				string[] array = text.Split('\n');
				foreach (string text2 in array)
				{
					string[] array2 = text2.Trim().Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
					if (array2.Length < 5 || !int.TryParse(array2[^1], out var result))
					{
						continue;
					}
					string text3 = array2[1];
					int num = text3.LastIndexOf(':');
					if (num >= 0)
					{
						string text4 = text3;
						int num2 = num + 1;
						if (int.TryParse(text4.Substring(num2, text4.Length - num2), out var result2))
						{
							_pidMap.TryAdd(result2, result);
						}
					}
				}
			}
		}
		catch (Exception ex2)
		{
			LogService.Warn("netstat 실행 실패: " + ex2.Message);
		}
		_cacheExpiry = DateTime.Now.AddSeconds(5.0);
	}

	private static string GetProcessNameForPort(int port)
	{
		int pidForPort = GetPidForPort(port);
		string value;
		return (pidForPort > 0 && _procCache.TryGetValue(pidForPort, out value)) ? value : "알 수 없음";
	}

	private static int GetPidForPort(int port)
	{
		int value;
		return _pidMap.TryGetValue(port, out value) ? value : (-1);
	}
}
