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;

namespace AxCopilot.Core;

public class CommandResolver
{
	private readonly FuzzyEngine _fuzzy;

	private readonly SettingsService _settings;

	private readonly Dictionary<string, IActionHandler> _handlers = new Dictionary<string, IActionHandler>();

	private readonly List<IActionHandler> _fuzzyHandlers = new List<IActionHandler>();

	public IReadOnlyDictionary<string, IActionHandler> RegisteredHandlers => _handlers;

	public CommandResolver(FuzzyEngine fuzzy, SettingsService settings)
	{
		_fuzzy = fuzzy;
		_settings = settings;
	}

	public void RegisterHandler(IActionHandler handler)
	{
		if (handler.Prefix == null)
		{
			_fuzzyHandlers.Add(handler);
			LogService.Info("FuzzyHandler 등록: name='" + handler.Metadata.Name + "'");
			return;
		}
		if (_handlers.ContainsKey(handler.Prefix))
		{
			LogService.Warn($"Prefix '{handler.Prefix}' 중복 등록: '{handler.Metadata.Name}'이 기존 핸들러를 덮어씁니다.");
		}
		_handlers[handler.Prefix] = handler;
		LogService.Info($"Handler 등록: prefix='{handler.Prefix}', name='{handler.Metadata.Name}'");
	}

	public async Task<IEnumerable<LauncherItem>> ResolveAsync(string input, CancellationToken ct)
	{
		if (string.IsNullOrWhiteSpace(input))
		{
			return Enumerable.Empty<LauncherItem>();
		}
		foreach (var (prefix, handler) in _handlers)
		{
			if (input.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
			{
				object obj;
				if (input.Length <= prefix.Length)
				{
					obj = "";
				}
				else
				{
					string text2 = input;
					int length = prefix.Length;
					obj = text2.Substring(length, text2.Length - length).Trim();
				}
				string query = (string)obj;
				try
				{
					return await handler.GetItemsAsync(query, ct);
				}
				catch (OperationCanceledException)
				{
					throw;
				}
				catch (Exception ex2)
				{
					LogService.Error("Handler '" + handler.Metadata.Name + "' 오류: " + ex2.Message);
					return new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("오류: " + ex2.Message, handler.Metadata.Name, null, null));
				}
			}
		}
		int maxResults = _settings.Settings.Launcher.MaxResults;
		HashSet<string> seenPaths = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
		List<LauncherItem> fuzzyItems = UsageRankingService.SortByUsage((from r in _fuzzy.Search(input, maxResults * 2)
			where seenPaths.Add(r.Entry.Path)
			select r).Take(maxResults).Select(delegate(FuzzyResult r)
		{
			string displayName = r.Entry.DisplayName;
			string subtitle;
			if (r.Entry.Type == IndexEntryType.Alias)
			{
				string aliasType = r.Entry.AliasType;
				if (1 == 0)
				{
				}
				string text3 = ((aliasType == "url") ? "URL 단축키" : ((!(aliasType == "batch")) ? r.Entry.Path : "명령 단축키"));
				if (1 == 0)
				{
				}
				subtitle = text3;
			}
			else
			{
				subtitle = r.Entry.Path + "  ⇧ Shift+Enter: 폴더 열기";
			}
			object entry = r.Entry;
			IndexEntryType type = r.Entry.Type;
			if (1 == 0)
			{
			}
			string symbol;
			switch (type)
			{
			case IndexEntryType.App:
				symbol = "\uecaa";
				break;
			case IndexEntryType.Folder:
				symbol = "\ue8b7";
				break;
			case IndexEntryType.Alias:
			{
				string aliasType2 = r.Entry.AliasType;
				if (1 == 0)
				{
				}
				string text3 = ((aliasType2 == "url") ? "\ue774" : ((!(aliasType2 == "batch")) ? "\uecca" : "\ue756"));
				if (1 == 0)
				{
				}
				symbol = text3;
				break;
			}
			default:
				symbol = "\ue8a5";
				break;
			}
			if (1 == 0)
			{
			}
			return new LauncherItem(displayName, subtitle, null, entry, null, symbol);
		}), (LauncherItem item) => (item.Data as IndexEntry)?.Path).ToList();
		if (_fuzzyHandlers.Count > 0)
		{
			List<Task<IEnumerable<LauncherItem>>> extraTasks = _fuzzyHandlers.Select((IActionHandler h) => SafeGetItemsAsync(h, input, ct)).ToList();
			await Task.WhenAll(extraTasks);
			foreach (Task<IEnumerable<LauncherItem>> task in extraTasks)
			{
				if (task.IsCompletedSuccessfully)
				{
					fuzzyItems.AddRange(task.Result.Take(3));
				}
			}
		}
		return fuzzyItems;
	}

	public async Task ExecuteAsync(LauncherItem item, string lastInput, CancellationToken ct)
	{
		foreach (var (prefix, handler) in _handlers)
		{
			if (lastInput.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
			{
				object obj;
				if (lastInput.Length <= prefix.Length)
				{
					obj = "";
				}
				else
				{
					int length = prefix.Length;
					obj = lastInput.Substring(length, lastInput.Length - length).Trim().Split(' ')[0];
				}
				string q = (string)obj;
				string cmdKey = (string.IsNullOrEmpty(q) ? prefix : (prefix + q));
				UsageStatisticsService.RecordCommandUsage(cmdKey);
				await handler.ExecuteAsync(item, ct);
				return;
			}
		}
		object data = item.Data;
		if (data is string urlData && urlData.StartsWith("http", StringComparison.OrdinalIgnoreCase))
		{
			await ExecuteNullPrefixAsync(item, ct);
			return;
		}
		data = item.Data;
		IndexEntry entry = data as IndexEntry;
		if (entry == null)
		{
			return;
		}
		string expanded = Environment.ExpandEnvironmentVariables(entry.Path);
		try
		{
			await Task.Run(() => Process.Start(new ProcessStartInfo(expanded)
			{
				UseShellExecute = true
			}));
		}
		catch (Exception ex)
		{
			Exception ex2 = ex;
			LogService.Error("실행 실패: " + expanded + " - " + ex2.Message);
		}
		Task.Run(delegate
		{
			UsageRankingService.RecordExecution(entry.Path);
		});
	}

	public async Task ExecuteNullPrefixAsync(LauncherItem item, CancellationToken ct)
	{
		foreach (IActionHandler handler in _fuzzyHandlers)
		{
			try
			{
				await handler.ExecuteAsync(item, ct);
				return;
			}
			catch (OperationCanceledException)
			{
				throw;
			}
			catch (Exception ex2)
			{
				LogService.Error("FuzzyHandler '" + handler.Metadata.Name + "' 실행 오류: " + ex2.Message);
			}
		}
	}

	private static async Task<IEnumerable<LauncherItem>> SafeGetItemsAsync(IActionHandler handler, string query, CancellationToken ct)
	{
		try
		{
			return await handler.GetItemsAsync(query, ct);
		}
		catch (OperationCanceledException)
		{
			throw;
		}
		catch (Exception ex2)
		{
			Exception ex3 = ex2;
			LogService.Error("FuzzyHandler '" + handler.Metadata.Name + "' 오류: " + ex3.Message);
			return Enumerable.Empty<LauncherItem>();
		}
	}
}
