using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
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;

namespace AxCopilot.Handlers;

public class ClipboardHandler : IActionHandler
{
	private readonly SettingsService _settings;

	public string? Prefix => "$";

	public PluginMetadata Metadata => new PluginMetadata("clipboard", "클립보드 변환", "1.0", "AX");

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

	public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
	{
		List<LauncherItem> list = new List<LauncherItem>();
		IEnumerable<ClipboardTransformer> enumerable = from t in GetBuiltinTransformers()
			where string.IsNullOrEmpty(query) || t.Key.Contains(query, StringComparison.OrdinalIgnoreCase)
			select t;
		foreach (ClipboardTransformer item in enumerable)
		{
			list.Add(new LauncherItem(item.Key, item.Description ?? "", null, item, null, "\ue77f"));
		}
		IEnumerable<LauncherItem> collection = from t in _settings.Settings.ClipboardTransformers
			where string.IsNullOrEmpty(query) || t.Key.Contains(query, StringComparison.OrdinalIgnoreCase)
			select new LauncherItem(t.Key, t.Description ?? t.Type, null, t, null, "\ue77f");
		list.AddRange(collection);
		return Task.FromResult((IEnumerable<LauncherItem>)list);
	}

	public async Task ExecuteAsync(LauncherItem item, CancellationToken ct)
	{
		object data = item.Data;
		if (!(data is ClipboardTransformer transformer))
		{
			return;
		}
		string input = null;
		((DispatcherObject)System.Windows.Application.Current).Dispatcher.Invoke((Action)delegate
		{
			input = (System.Windows.Clipboard.ContainsText() ? System.Windows.Clipboard.GetText() : null);
		});
		if (input == null)
		{
			return;
		}
		string result = await TransformAsync(transformer, input, ct);
		if (result != null)
		{
			((DispatcherObject)System.Windows.Application.Current).Dispatcher.Invoke((Action)delegate
			{
				System.Windows.Clipboard.SetText(result);
			});
			nint prevHwnd = WindowTracker.PreviousWindow;
			if (prevHwnd != IntPtr.Zero)
			{
				SetForegroundWindow(prevHwnd);
			}
			await Task.Delay(120, ct);
			SendKeys.SendWait("^v");
			LogService.Info("클립보드 변환: '" + transformer.Key + "' 적용");
		}
	}

	private static async Task<string?> TransformAsync(ClipboardTransformer t, string input, CancellationToken ct)
	{
		try
		{
			string type = t.Type;
			if (1 == 0)
			{
			}
			string text = type;
			string result;
			if (!(text == "regex"))
			{
				if (!(text == "script") || t.Command == null)
				{
					goto IL_016f;
				}
				result = await RunScriptAsync(t.Command, input, t.Timeout, ct);
			}
			else
			{
				if (t.Pattern == null || t.Replace == null)
				{
					goto IL_016f;
				}
				result = Regex.Replace(input, t.Pattern, t.Replace, RegexOptions.None, TimeSpan.FromMilliseconds((t.Timeout > 0) ? t.Timeout : 5000));
			}
			goto IL_0188;
			IL_016f:
			result = ExecuteBuiltin(t.Key, input);
			goto IL_0188;
			IL_0188:
			if (1 == 0)
			{
			}
			return result;
		}
		catch (Exception ex)
		{
			Exception ex2 = ex;
			LogService.Error("변환 실패 (" + t.Key + "): " + ex2.Message);
			return null;
		}
	}

	private static async Task<string> RunScriptAsync(string command, string input, int timeoutMs, CancellationToken ct)
	{
		using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
		cts.CancelAfter(timeoutMs);
		string[] parts = command.Split(' ', 2);
		ProcessStartInfo psi = new ProcessStartInfo(parts[0])
		{
			Arguments = ((parts.Length > 1) ? parts[1] : ""),
			RedirectStandardInput = true,
			RedirectStandardOutput = true,
			UseShellExecute = false,
			CreateNoWindow = true,
			StandardInputEncoding = Encoding.UTF8,
			StandardOutputEncoding = Encoding.UTF8
		};
		using Process proc = Process.Start(psi);
		await proc.StandardInput.WriteAsync(input);
		proc.StandardInput.Close();
		return await proc.StandardOutput.ReadToEndAsync(cts.Token);
	}

	internal static string? ExecuteBuiltin(string key, string input)
	{
		if (1 == 0)
		{
		}
		string result = key switch
		{
			"$json" => FormatJson(input), 
			"$upper" => input.ToUpperInvariant(), 
			"$lower" => input.ToLowerInvariant(), 
			"$ts" => TryParseTimestamp(input), 
			"$epoch" => TryParseDate(input), 
			"$urle" => Uri.EscapeDataString(input), 
			"$urld" => Uri.UnescapeDataString(input), 
			"$b64e" => Convert.ToBase64String(Encoding.UTF8.GetBytes(input)), 
			"$b64d" => Encoding.UTF8.GetString(Convert.FromBase64String(input)), 
			"$md" => StripMarkdown(input), 
			"$trim" => input.Trim(), 
			"$lines" => string.Join(Environment.NewLine, from l in input.Split('\n')
				select l.Trim() into l
				where l.Length > 0
				select l), 
			_ => null, 
		};
		if (1 == 0)
		{
		}
		return result;
	}

	private static string FormatJson(string input)
	{
		try
		{
			JsonDocument value = JsonDocument.Parse(input);
			return JsonSerializer.Serialize(value, new JsonSerializerOptions
			{
				WriteIndented = true
			});
		}
		catch
		{
			return input;
		}
	}

	private static string? TryParseTimestamp(string input)
	{
		if (long.TryParse(input.Trim(), out var result))
		{
			return DateTimeOffset.FromUnixTimeSeconds(result).LocalDateTime.ToString("yyyy-MM-dd HH:mm:ss");
		}
		return null;
	}

	private static string? TryParseDate(string input)
	{
		if (DateTime.TryParse(input.Trim(), out var result))
		{
			return new DateTimeOffset(result).ToUnixTimeSeconds().ToString();
		}
		return null;
	}

	private static string StripMarkdown(string input)
	{
		return Regex.Replace(input, "(\\*\\*|__)(.*?)\\1|(\\*|_)(.*?)\\3|`(.+?)`|#{1,6}\\s*", "$2$4$5");
	}

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

	private static IEnumerable<ClipboardTransformer> GetBuiltinTransformers()
	{
		return new _003C_003Ez__ReadOnlyArray<ClipboardTransformer>(new ClipboardTransformer[12]
		{
			new ClipboardTransformer
			{
				Key = "$json",
				Type = "builtin",
				Description = "JSON 포맷팅 (들여쓰기 적용)"
			},
			new ClipboardTransformer
			{
				Key = "$upper",
				Type = "builtin",
				Description = "대문자 변환"
			},
			new ClipboardTransformer
			{
				Key = "$lower",
				Type = "builtin",
				Description = "소문자 변환"
			},
			new ClipboardTransformer
			{
				Key = "$ts",
				Type = "builtin",
				Description = "유닉스 타임스탬프 → 날짜 문자열"
			},
			new ClipboardTransformer
			{
				Key = "$epoch",
				Type = "builtin",
				Description = "날짜 문자열 → 유닉스 타임스탬프"
			},
			new ClipboardTransformer
			{
				Key = "$urle",
				Type = "builtin",
				Description = "URL 인코딩"
			},
			new ClipboardTransformer
			{
				Key = "$urld",
				Type = "builtin",
				Description = "URL 디코딩"
			},
			new ClipboardTransformer
			{
				Key = "$b64e",
				Type = "builtin",
				Description = "Base64 인코딩"
			},
			new ClipboardTransformer
			{
				Key = "$b64d",
				Type = "builtin",
				Description = "Base64 디코딩"
			},
			new ClipboardTransformer
			{
				Key = "$md",
				Type = "builtin",
				Description = "마크다운 문법 제거"
			},
			new ClipboardTransformer
			{
				Key = "$trim",
				Type = "builtin",
				Description = "앞뒤 공백 제거"
			},
			new ClipboardTransformer
			{
				Key = "$lines",
				Type = "builtin",
				Description = "빈 줄 제거 및 각 줄 공백 정리"
			}
		});
	}
}
