using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Threading;
using AxCopilot.Models;
using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Views;

namespace AxCopilot.Handlers;

public class SystemCommandHandler : IActionHandler
{
	private readonly SettingsService _settings;

	private static readonly Regex _timerRe = new Regex("^(?:(?:(\\d+)h)?(?:(\\d+)m)?(?:(\\d+)s)?)$", RegexOptions.IgnoreCase | RegexOptions.Compiled);

	private static readonly Regex _alarmRe = new Regex("^(\\d{1,2}):(\\d{2})$", RegexOptions.Compiled);

	public string? Prefix => "/";

	public PluginMetadata Metadata => new PluginMetadata("SystemCommands", "시스템 명령 — / 뒤에 명령 입력", "1.0", "AX");

	public SystemCommandHandler(SettingsService settings)
	{
		_settings = settings;
	}

	public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
	{
		SystemCommandSettings cfg = _settings.Settings.SystemCommands;
		string q = query.Trim().ToLowerInvariant();
		if (q.StartsWith("timer"))
		{
			string text = q;
			string text2 = text.Substring(5, text.Length - 5).Trim();
			List<LauncherItem> list = new List<LauncherItem>();
			if (string.IsNullOrEmpty(text2))
			{
				list.Add(new LauncherItem("타이머 — 시간을 입력하세요", "예: /timer 5m · /timer 1h30m · /timer 30s 회의", null, null, null, "\ue916"));
				return Task.FromResult((IEnumerable<LauncherItem>)list);
			}
			string[] array = text2.Split(' ', 2);
			string s = array[0];
			string label = ((array.Length > 1) ? array[1].Trim() : "");
			if (TryParseTimer(s, out var seconds) && seconds > 0)
			{
				string display = FormatDuration(seconds);
				string title = (string.IsNullOrEmpty(label) ? ("타이머 " + display) : ("타이머 " + display + " — " + label));
				list.Add(new LauncherItem(title, display + " 후 알림  ·  Enter로 시작", null, (Func<Task>)(() => StartTimerAsync(seconds, (label.Length > 0) ? label : display)), null, "\ue916"));
			}
			else
			{
				list.Add(new LauncherItem("형식 오류", "예: /timer 5m · /timer 1h30m · /timer 90s", null, null, null, "\uea39"));
			}
			return Task.FromResult((IEnumerable<LauncherItem>)list);
		}
		if (q.StartsWith("alarm"))
		{
			string text = q;
			string text3 = text.Substring(5, text.Length - 5).Trim();
			List<LauncherItem> list2 = new List<LauncherItem>();
			if (string.IsNullOrEmpty(text3))
			{
				list2.Add(new LauncherItem("알람 — 시각을 입력하세요", "예: /alarm 14:30 · /alarm 9:00", null, null, null, "\ue916"));
				return Task.FromResult((IEnumerable<LauncherItem>)list2);
			}
			Match match = _alarmRe.Match(text3.Split(' ')[0]);
			if (match.Success)
			{
				int num = int.Parse(match.Groups[1].Value);
				int num2 = int.Parse(match.Groups[2].Value);
				object obj;
				if (!text3.Contains(' '))
				{
					obj = "";
				}
				else
				{
					text = text3;
					int num3 = text3.IndexOf(' ') + 1;
					obj = text.Substring(num3, text.Length - num3);
				}
				string label2 = (string)obj;
				if (num >= 0 && num <= 23 && num2 >= 0 && num2 <= 59)
				{
					DateTime dateTime = DateTime.Today.AddHours(num).AddMinutes(num2);
					if (dateTime <= DateTime.Now)
					{
						dateTime = dateTime.AddDays(1.0);
					}
					int diff = (int)(dateTime - DateTime.Now).TotalSeconds;
					string timeStr = dateTime.ToString("HH:mm");
					list2.Add(new LauncherItem("알람  " + timeStr + "  " + ((dateTime.Date > DateTime.Today) ? "(내일)" : ""), (FormatDuration(diff) + " 후 알림  ·  Enter로 시작  " + ((label2.Length > 0) ? ("— " + label2) : "")).Trim(), null, (Func<Task>)(() => StartTimerAsync(diff, (label2.Length > 0) ? label2 : (timeStr + " 알람"))), null, "\ue916"));
				}
				else
				{
					list2.Add(new LauncherItem("시각 범위 오류", "00:00 ~ 23:59 범위로 입력하세요", null, null, null, "\uea39"));
				}
			}
			else
			{
				list2.Add(new LauncherItem("형식 오류", "예: /alarm 14:30 · /alarm 09:00", null, null, null, "\uea39"));
			}
			return Task.FromResult((IEnumerable<LauncherItem>)list2);
		}
		List<(string, string, string, string, bool, Func<Task>)> list3 = new List<(string, string, string, string, bool, Func<Task>)>();
		list3.Add(("lock", "화면 잠금", "현재 세션을 잠급니다", "\ue72e", cfg.ShowLock, LockAsync));
		list3.Add(("sleep", "절전 모드", "시스템을 절전 상태로 전환합니다", "\uec46", cfg.ShowSleep, SleepAsync));
		list3.Add(("restart", "재시작", "컴퓨터를 재시작합니다", "\ue777", cfg.ShowRestart, RestartAsync));
		list3.Add(("shutdown", "시스템 종료", "컴퓨터를 종료합니다", "\ue7e8", cfg.ShowShutdown, ShutdownAsync));
		list3.Add(("hibernate", "최대 절전", "최대 절전 모드로 전환합니다", "\uec46", cfg.ShowHibernate, HibernateAsync));
		list3.Add(("logout", "로그아웃", "현재 사용자 세션에서 로그아웃합니다", "\uf3b1", cfg.ShowLogout, LogoutAsync));
		list3.Add(("recycle", "휴지통 비우기", "휴지통의 모든 파일을 영구 삭제합니다", "\ue74d", cfg.ShowRecycleBin, EmptyRecycleBinAsync));
		list3.Add(("dock", "독 바 표시/숨기기", "화면 하단 독 바를 표시하거나 숨깁니다", "\ue8a0", true, ToggleDockAsync));
		List<(string, string, string, string, bool, Func<Task>)> source = list3;
		List<string> value;
		IEnumerable<LauncherItem> source2 = from c in source
			where c.Enabled
			where string.IsNullOrEmpty(q) || c.Key.StartsWith(q) || c.Name.Contains(q) || (cfg.CommandAliases.TryGetValue(c.Key, out value) && value.Any((string a) => a.StartsWith(q, StringComparison.OrdinalIgnoreCase)))
			select new LauncherItem(c.Name, c.Hint, null, c.Action, null, c.Symbol);
		return Task.FromResult((IEnumerable<LauncherItem>)source2.ToList());
	}

	public async Task ExecuteAsync(LauncherItem item, CancellationToken ct)
	{
		object data = item.Data;
		Func<Task> action = data as Func<Task>;
		if (action != null)
		{
			await action();
		}
	}

	private static async Task StartTimerAsync(int totalSeconds, string label)
	{
		await Task.Delay(TimeSpan.FromSeconds(totalSeconds));
		NotificationService.Notify("⏰ 타이머 완료", label);
	}

	private static bool TryParseTimer(string s, out int totalSeconds)
	{
		totalSeconds = 0;
		Match match = _timerRe.Match(s.ToLowerInvariant());
		if (!match.Success)
		{
			return false;
		}
		int num = (match.Groups[1].Success ? int.Parse(match.Groups[1].Value) : 0);
		int num2 = (match.Groups[2].Success ? int.Parse(match.Groups[2].Value) : 0);
		int num3 = (match.Groups[3].Success ? int.Parse(match.Groups[3].Value) : 0);
		totalSeconds = num * 3600 + num2 * 60 + num3;
		return true;
	}

	private static string FormatDuration(int totalSeconds)
	{
		int num = totalSeconds / 3600;
		int num2 = totalSeconds % 3600 / 60;
		int num3 = totalSeconds % 60;
		if (num > 0 && num2 > 0)
		{
			return $"{num}시간 {num2}분";
		}
		if (num <= 0)
		{
			if (num2 > 0 && num3 > 0)
			{
				return $"{num2}분 {num3}초";
			}
			if (num2 <= 0)
			{
				return $"{num3}초";
			}
			return $"{num2}분";
		}
		return $"{num}시간";
	}

	private static Task LockAsync()
	{
		LockWorkStation();
		return Task.CompletedTask;
	}

	private static Task SleepAsync()
	{
		System.Windows.Forms.Application.SetSuspendState(PowerState.Suspend, force: false, disableWakeEvent: false);
		return Task.CompletedTask;
	}

	private static Task HibernateAsync()
	{
		System.Windows.Forms.Application.SetSuspendState(PowerState.Hibernate, force: false, disableWakeEvent: false);
		return Task.CompletedTask;
	}

	private static Task RestartAsync()
	{
		MessageBoxResult messageBoxResult = CustomMessageBox.Show("컴퓨터를 재시작하시겠습니까?\n저장되지 않은 작업이 있으면 먼저 저장하세요.", "재시작 확인", MessageBoxButton.YesNo, MessageBoxImage.Question);
		if (messageBoxResult == MessageBoxResult.Yes)
		{
			Process.Start(new ProcessStartInfo("shutdown", "/r /t 5 /c \"AX Copilot에 의해 재시작됩니다.\"")
			{
				UseShellExecute = true,
				CreateNoWindow = true
			});
		}
		return Task.CompletedTask;
	}

	private static Task ShutdownAsync()
	{
		MessageBoxResult messageBoxResult = CustomMessageBox.Show("컴퓨터를 종료하시겠습니까?\n저장되지 않은 작업이 있으면 먼저 저장하세요.", "종료 확인", MessageBoxButton.YesNo, MessageBoxImage.Question);
		if (messageBoxResult == MessageBoxResult.Yes)
		{
			Process.Start(new ProcessStartInfo("shutdown", "/s /t 5 /c \"AX Copilot에 의해 종료됩니다.\"")
			{
				UseShellExecute = true,
				CreateNoWindow = true
			});
		}
		return Task.CompletedTask;
	}

	private static Task LogoutAsync()
	{
		MessageBoxResult messageBoxResult = CustomMessageBox.Show("로그아웃하시겠습니까?", "로그아웃 확인", MessageBoxButton.YesNo, MessageBoxImage.Question);
		if (messageBoxResult == MessageBoxResult.Yes)
		{
			ExitWindowsEx(0u, 0u);
		}
		return Task.CompletedTask;
	}

	private static Task EmptyRecycleBinAsync()
	{
		MessageBoxResult messageBoxResult = CustomMessageBox.Show("휴지통을 비우시겠습니까?\n삭제된 파일은 복구할 수 없습니다.", "휴지통 비우기", MessageBoxButton.YesNo, MessageBoxImage.Exclamation);
		if (messageBoxResult == MessageBoxResult.Yes)
		{
			SHEmptyRecycleBin(IntPtr.Zero, null, 7u);
		}
		return Task.CompletedTask;
	}

	private static Task ToggleDockAsync()
	{
		((DispatcherObject)System.Windows.Application.Current).Dispatcher.Invoke((Action)delegate
		{
			(System.Windows.Application.Current as App)?.ToggleDockBar();
		});
		return Task.CompletedTask;
	}

	[DllImport("user32.dll", SetLastError = true)]
	private static extern bool LockWorkStation();

	[DllImport("user32.dll", SetLastError = true)]
	private static extern bool ExitWindowsEx(uint uFlags, uint dwReason);

	[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
	private static extern uint SHEmptyRecycleBin(nint hwnd, string? pszRootPath, uint dwFlags);
}
