using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using AxCopilot.SDK;

namespace AxCopilot.Handlers;

public class WindowSwitchHandler : IActionHandler
{
	private delegate bool EnumWindowsProc(nint hWnd, nint lParam);

	private record WindowInfo(nint Handle, string Title, string ProcessName, bool IsMinimized);

	private const int SW_RESTORE = 9;

	public string? Prefix => "win";

	public PluginMetadata Metadata => new PluginMetadata("WindowSwitch", "윈도우 포커스 스위처 — win", "1.0", "AX");

	[DllImport("user32.dll")]
	private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, nint lParam);

	[DllImport("user32.dll")]
	private static extern bool IsWindowVisible(nint hWnd);

	[DllImport("user32.dll")]
	private static extern int GetWindowTextLength(nint hWnd);

	[DllImport("user32.dll")]
	private static extern int GetWindowText(nint hWnd, StringBuilder lpString, int nMaxCount);

	[DllImport("user32.dll")]
	private static extern uint GetWindowThreadProcessId(nint hWnd, out uint lpdwProcessId);

	[DllImport("user32.dll")]
	private static extern bool SetForegroundWindow(nint hWnd);

	[DllImport("user32.dll")]
	private static extern bool ShowWindow(nint hWnd, int nCmdShow);

	[DllImport("user32.dll")]
	private static extern bool IsIconic(nint hWnd);

	[DllImport("user32.dll")]
	private static extern nint GetShellWindow();

	public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
	{
		string q = query.Trim();
		List<WindowInfo> list = GetOpenWindows();
		if (!string.IsNullOrWhiteSpace(q))
		{
			list = list.Where((WindowInfo w) => w.Title.Contains(q, StringComparison.OrdinalIgnoreCase) || w.ProcessName.Contains(q, StringComparison.OrdinalIgnoreCase)).ToList();
		}
		if (!list.Any())
		{
			return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem(string.IsNullOrWhiteSpace(q) ? "열린 창이 없습니다" : ("'" + q + "'에 해당하는 창 없음"), "win 뒤에 프로세스명 또는 창 제목 입력", null, null, null, "\ue946")));
		}
		List<LauncherItem> list2 = (from w in list.Take(15)
			select new LauncherItem((w.Title.Length > 60) ? (w.Title.Substring(0, 57) + "…") : w.Title, w.ProcessName + "  ·  " + (w.IsMinimized ? "[최소화됨]  ·  " : "") + "Enter → 전환", null, w.Handle, null, "\ue7f4")).ToList();
		list2.Insert(0, new LauncherItem($"열린 창 {list.Count}개", "Enter → 해당 창으로 즉시 전환", null, null, null, "\ue946"));
		return Task.FromResult((IEnumerable<LauncherItem>)list2);
	}

	public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
	{
		if (item.Data is nint num && num != IntPtr.Zero)
		{
			if (IsIconic(num))
			{
				ShowWindow(num, 9);
			}
			SetForegroundWindow(num);
		}
		return Task.CompletedTask;
	}

	private static List<WindowInfo> GetOpenWindows()
	{
		List<WindowInfo> list = new List<WindowInfo>();
		nint shellWnd = GetShellWindow();
		string currentProcessName = Process.GetCurrentProcess().ProcessName;
		EnumWindows(delegate(nint hWnd, nint _)
		{
			if (hWnd == shellWnd)
			{
				return true;
			}
			if (!IsWindowVisible(hWnd))
			{
				return true;
			}
			int windowTextLength = GetWindowTextLength(hWnd);
			if (windowTextLength == 0)
			{
				return true;
			}
			StringBuilder stringBuilder = new StringBuilder(windowTextLength + 1);
			GetWindowText(hWnd, stringBuilder, stringBuilder.Capacity);
			string title = stringBuilder.ToString();
			string text = "";
			try
			{
				GetWindowThreadProcessId(hWnd, out var lpdwProcessId);
				text = Process.GetProcessById((int)lpdwProcessId).ProcessName;
			}
			catch
			{
			}
			if (text == currentProcessName)
			{
				return true;
			}
			bool flag;
			switch (text)
			{
			case "ApplicationFrameHost":
			case "ShellExperienceHost":
			case "SearchHost":
			case "StartMenuExperienceHost":
			case "TextInputHost":
				flag = true;
				break;
			default:
				flag = false;
				break;
			}
			if (flag)
			{
				return true;
			}
			list.Add(new WindowInfo(hWnd, title, text, IsIconic(hWnd)));
			return true;
		}, IntPtr.Zero);
		return list;
	}
}
