using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using AxCopilot.SDK;
using AxCopilot.Services;

namespace AxCopilot.Handlers;

public class EverythingHandler : IActionHandler
{
	private const int EVERYTHING_OK = 0;

	private const int EVERYTHING_REQUEST_FILE_NAME = 1;

	private const int EVERYTHING_REQUEST_PATH = 2;

	private const int EVERYTHING_REQUEST_SIZE = 16;

	private bool? _isAvailable;

	public string? Prefix => "es";

	public PluginMetadata Metadata => new PluginMetadata("EverythingSearch", "Everything 초고속 파일 검색 — es [키워드]", "1.0", "AX");

	private bool IsAvailable
	{
		get
		{
			if (_isAvailable.HasValue)
			{
				return _isAvailable.Value;
			}
			try
			{
				Everything_GetMajorVersion();
				_isAvailable = true;
			}
			catch
			{
				_isAvailable = false;
			}
			return _isAvailable.Value;
		}
	}

	[DllImport("Everything64.dll", CharSet = CharSet.Unicode)]
	private static extern uint Everything_SetSearchW(string lpSearchString);

	[DllImport("Everything64.dll")]
	private static extern void Everything_SetMax(uint dwMax);

	[DllImport("Everything64.dll")]
	private static extern void Everything_SetRequestFlags(uint dwRequestFlags);

	[DllImport("Everything64.dll")]
	private static extern bool Everything_QueryW(bool bWait);

	[DllImport("Everything64.dll")]
	private static extern uint Everything_GetNumResults();

	[DllImport("Everything64.dll")]
	private static extern uint Everything_GetLastError();

	[DllImport("Everything64.dll", CharSet = CharSet.Unicode)]
	private static extern nint Everything_GetResultFullPathNameW(uint nIndex, nint lpString, uint nMaxCount);

	[DllImport("Everything64.dll", CharSet = CharSet.Unicode)]
	private static extern void Everything_GetResultSize(uint nIndex, out long lpFileSize);

	[DllImport("Everything64.dll")]
	private static extern uint Everything_GetMajorVersion();

	public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
	{
		if (!IsAvailable)
		{
			return Task.FromResult((IEnumerable<LauncherItem>)new LauncherItem[1]
			{
				new LauncherItem("Everything이 설치되어 있지 않습니다", "voidtools.com에서 Everything을 설치하면 초고속 파일 검색을 사용할 수 있습니다", null, null, null, "\ue7ba")
			});
		}
		string text = query.Trim();
		if (string.IsNullOrWhiteSpace(text))
		{
			return Task.FromResult((IEnumerable<LauncherItem>)new LauncherItem[1]
			{
				new LauncherItem("Everything 파일 검색", "검색어를 입력하세요 — 파일명, 확장자(*.xlsx), 경로 일부 등", null, null, null, "\ue721")
			});
		}
		try
		{
			Everything_SetSearchW(text);
			Everything_SetMax(30u);
			Everything_SetRequestFlags(19u);
			if (!Everything_QueryW(bWait: true))
			{
				return Task.FromResult((IEnumerable<LauncherItem>)new LauncherItem[1]
				{
					new LauncherItem("Everything 검색 실패", $"오류 코드: {Everything_GetLastError()} — Everything 서비스가 실행 중인지 확인하세요", null, null, null, "\ue7ba")
				});
			}
			uint num = Everything_GetNumResults();
			if (num == 0)
			{
				return Task.FromResult((IEnumerable<LauncherItem>)new LauncherItem[1]
				{
					new LauncherItem("검색 결과 없음: " + text, "다른 키워드나 와일드카드(*.xlsx)를 시도해 보세요", null, null, null, "\ue946")
				});
			}
			List<LauncherItem> list = new List<LauncherItem>();
			nint num2 = Marshal.AllocHGlobal(1040);
			try
			{
				for (uint num3 = 0u; num3 < num && num3 < 30; num3++)
				{
					Everything_GetResultFullPathNameW(num3, num2, 520u);
					string text2 = Marshal.PtrToStringUni(num2) ?? "";
					Everything_GetResultSize(num3, out var lpFileSize);
					string fileName = Path.GetFileName(text2);
					string text3 = Path.GetDirectoryName(text2) ?? "";
					string text4 = ((lpFileSize > 0) ? FormatSize(lpFileSize) : "");
					string subtitle = (string.IsNullOrEmpty(text4) ? text3 : (text4 + "  ·  " + text3));
					string symbol = (Directory.Exists(text2) ? "\ue8b7" : GetFileSymbol(text2));
					list.Add(new LauncherItem(fileName, subtitle, null, text2, null, symbol));
				}
			}
			finally
			{
				Marshal.FreeHGlobal(num2);
			}
			return Task.FromResult((IEnumerable<LauncherItem>)list);
		}
		catch (Exception ex)
		{
			LogService.Warn("Everything 검색 오류: " + ex.Message);
			return Task.FromResult((IEnumerable<LauncherItem>)new LauncherItem[1]
			{
				new LauncherItem("Everything 검색 오류", ex.Message, null, null, null, "\ue7ba")
			});
		}
	}

	public async Task ExecuteAsync(LauncherItem item, CancellationToken ct)
	{
		object data = item.Data;
		string path = data as string;
		if (path == null || string.IsNullOrEmpty(path))
		{
			return;
		}
		try
		{
			if (Directory.Exists(path))
			{
				Process.Start(new ProcessStartInfo
				{
					FileName = path,
					UseShellExecute = true
				});
			}
			else if (File.Exists(path))
			{
				Process.Start(new ProcessStartInfo
				{
					FileName = path,
					UseShellExecute = true
				});
			}
		}
		catch (Exception ex)
		{
			Exception ex2 = ex;
			LogService.Warn("Everything 결과 열기 실패: " + ex2.Message);
		}
		await Task.CompletedTask;
	}

	private static string FormatSize(long bytes)
	{
		if (bytes >= 1024)
		{
			if (bytes >= 1048576)
			{
				if (bytes >= 1073741824)
				{
					return $"{(double)bytes / 1073741824.0:F2} GB";
				}
				return $"{(double)bytes / 1048576.0:F1} MB";
			}
			return $"{(double)bytes / 1024.0:F1} KB";
		}
		return $"{bytes} B";
	}

	private static string GetFileSymbol(string path)
	{
		string text = Path.GetExtension(path).ToLowerInvariant();
		if (1 == 0)
		{
		}
		string result;
		switch (text)
		{
		case ".xlsx":
		case ".xls":
		case ".csv":
			result = "\ue9f9";
			break;
		case ".docx":
		case ".doc":
			result = "\ue8a5";
			break;
		case ".pptx":
		case ".ppt":
			result = "\uee71";
			break;
		case ".pdf":
			result = "\uea90";
			break;
		case ".png":
		case ".jpg":
		case ".jpeg":
		case ".gif":
		case ".bmp":
		case ".svg":
			result = "\ueb9f";
			break;
		case ".mp4":
		case ".avi":
		case ".mkv":
		case ".mov":
			result = "\ue714";
			break;
		case ".mp3":
		case ".wav":
		case ".flac":
			result = "\uec4f";
			break;
		case ".zip":
		case ".rar":
		case ".7z":
		case ".tar":
		case ".gz":
			result = "\ue8c6";
			break;
		case ".exe":
		case ".msi":
			result = "\uecaa";
			break;
		case ".cs":
		case ".py":
		case ".js":
		case ".ts":
		case ".java":
		case ".cpp":
		case ".c":
		case ".go":
			result = "\ue943";
			break;
		case ".json":
		case ".xml":
		case ".yaml":
		case ".yml":
			result = "\ue713";
			break;
		case ".txt":
		case ".md":
		case ".log":
			result = "\ue8d2";
			break;
		case ".html":
		case ".htm":
		case ".css":
			result = "\ue774";
			break;
		default:
			result = "\ue8a5";
			break;
		}
		if (1 == 0)
		{
		}
		return result;
	}
}
