using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using AxCopilot.SDK;
using AxCopilot.Services;
using Microsoft.Win32;

namespace AxCopilot.Handlers;

public class DiffHandler : IActionHandler
{
	private record DiffResult(string Text, int Added, int Removed, int Same);

	private readonly ClipboardHistoryService? _clipHistory;

	public string? Prefix => "diff";

	public PluginMetadata Metadata => new PluginMetadata("Diff", "텍스트/파일 비교 — diff", "1.0", "AX");

	public DiffHandler(ClipboardHistoryService? clipHistory = null)
	{
		_clipHistory = clipHistory;
	}

	public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
	{
		string text = query.Trim();
		if (!string.IsNullOrWhiteSpace(text))
		{
			string[] array = text.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
			if (array.Length == 2 && File.Exists(array[0]) && File.Exists(array[1]))
			{
				try
				{
					string textA = File.ReadAllText(array[0]);
					string textB = File.ReadAllText(array[1]);
					DiffResult diffResult = BuildDiff(textA, textB, Path.GetFileName(array[0]), Path.GetFileName(array[1]));
					return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("파일 비교: " + Path.GetFileName(array[0]) + " ↔ " + Path.GetFileName(array[1]), $"{diffResult.Added}줄 추가, {diffResult.Removed}줄 삭제, {diffResult.Same}줄 동일  ·  Enter로 결과 복사", null, diffResult.Text, null, "\ue8a5")));
				}
				catch (Exception ex)
				{
					return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("파일 읽기 실패: " + ex.Message, "", null, null, null, "\uea39")));
				}
			}
			if (array.Length >= 1 && (File.Exists(array[0]) || Directory.Exists(Path.GetDirectoryName(array[0]) ?? "")))
			{
				return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("비교할 파일 2개의 경로를 입력하세요", "예: diff C:\\a.txt C:\\b.txt", null, null, null, "\ue946")));
			}
		}
		IReadOnlyList<ClipboardEntry> readOnlyList = _clipHistory?.History;
		if (readOnlyList == null || readOnlyList.Count < 2)
		{
			return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("비교할 텍스트가 부족합니다", "클립보드에 2개 이상의 텍스트를 복사하거나, diff [파일A] [파일B]로 파일 비교", null, null, null, "\ue946")));
		}
		List<ClipboardEntry> list = readOnlyList.Where((ClipboardEntry e) => e.IsText).Take(2).ToList();
		if (list.Count < 2)
		{
			return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("텍스트 히스토리가 2개 미만입니다", "텍스트를 2번 이상 복사하세요", null, null, null, "\ue946")));
		}
		ClipboardEntry clipboardEntry = list[1];
		ClipboardEntry clipboardEntry2 = list[0];
		DiffResult diffResult2 = BuildDiff(clipboardEntry.Text, clipboardEntry2.Text, "이전 (" + clipboardEntry.RelativeTime + ")", "최근 (" + clipboardEntry2.RelativeTime + ")");
		List<LauncherItem> list2 = new List<LauncherItem>
		{
			new LauncherItem($"클립보드 비교: +{diffResult2.Added} -{diffResult2.Removed} ={diffResult2.Same}", "이전 복사 ↔ 최근 복사  ·  Enter로 결과 복사", null, diffResult2.Text, null, "\ue81c")
		};
		IEnumerable<string> enumerable = (from l in diffResult2.Text.Split('\n')
			where l.StartsWith("+ ") || l.StartsWith("- ")
			select l).Take(5);
		foreach (string item in enumerable)
		{
			string symbol = (item.StartsWith("+ ") ? "\ue710" : "\ue711");
			list2.Add(new LauncherItem(item, "", null, null, null, symbol));
		}
		list2.Add(new LauncherItem("파일 선택하여 비교", "파일 선택 대화 상자에서 2개의 파일을 골라 비교합니다", null, "__FILE_DIALOG__", null, "\ue8a5"));
		return Task.FromResult((IEnumerable<LauncherItem>)list2);
	}

	public async Task ExecuteAsync(LauncherItem item, CancellationToken ct)
	{
		object data = item.Data;
		if (data is string s && s == "__FILE_DIALOG__")
		{
			await Task.Delay(200, ct);
			Application current = Application.Current;
			if (current == null)
			{
				return;
			}
			((DispatcherObject)current).Dispatcher.Invoke((Action)delegate
			{
				OpenFileDialog openFileDialog = new OpenFileDialog
				{
					Title = "비교할 첫 번째 파일 선택",
					Filter = "텍스트 파일|*.txt;*.cs;*.json;*.xml;*.md;*.csv;*.log|모든 파일|*.*"
				};
				if (openFileDialog.ShowDialog() == true)
				{
					string fileName = openFileDialog.FileName;
					openFileDialog.Title = "비교할 두 번째 파일 선택";
					if (openFileDialog.ShowDialog() == true)
					{
						string fileName2 = openFileDialog.FileName;
						try
						{
							string textA = File.ReadAllText(fileName);
							string textB = File.ReadAllText(fileName2);
							DiffResult diffResult = BuildDiff(textA, textB, Path.GetFileName(fileName), Path.GetFileName(fileName2));
							Clipboard.SetText(diffResult.Text);
							NotificationService.Notify("파일 비교 완료", $"+{diffResult.Added} -{diffResult.Removed} ={diffResult.Same}  ·  결과 클립보드 복사됨");
						}
						catch (Exception ex)
						{
							NotificationService.Notify("비교 실패", ex.Message);
						}
					}
				}
			});
			return;
		}
		data = item.Data;
		string text = data as string;
		if (text == null || string.IsNullOrWhiteSpace(text))
		{
			return;
		}
		try
		{
			Application current2 = Application.Current;
			if (current2 != null)
			{
				((DispatcherObject)current2).Dispatcher.Invoke((Action)delegate
				{
					Clipboard.SetText(text);
				});
			}
		}
		catch
		{
		}
		NotificationService.Notify("비교 결과", "클립보드에 복사되었습니다");
	}

	private static DiffResult BuildDiff(string textA, string textB, string labelA, string labelB)
	{
		string[] array = (from l in textA.Split('\n')
			select l.TrimEnd('\r')).ToArray();
		string[] array2 = (from l in textB.Split('\n')
			select l.TrimEnd('\r')).ToArray();
		HashSet<string> hashSet = new HashSet<string>(array);
		HashSet<string> hashSet2 = new HashSet<string>(array2);
		StringBuilder stringBuilder = new StringBuilder();
		StringBuilder stringBuilder2 = stringBuilder;
		StringBuilder stringBuilder3 = stringBuilder2;
		StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(4, 1, stringBuilder2);
		handler.AppendLiteral("--- ");
		handler.AppendFormatted(labelA);
		stringBuilder3.AppendLine(ref handler);
		stringBuilder2 = stringBuilder;
		StringBuilder stringBuilder4 = stringBuilder2;
		handler = new StringBuilder.AppendInterpolatedStringHandler(4, 1, stringBuilder2);
		handler.AppendLiteral("+++ ");
		handler.AppendFormatted(labelB);
		stringBuilder4.AppendLine(ref handler);
		stringBuilder.AppendLine();
		int num = 0;
		int num2 = 0;
		int num3 = 0;
		int num4 = Math.Max(array.Length, array2.Length);
		for (int num5 = 0; num5 < num4; num5++)
		{
			string text = ((num5 < array.Length) ? array[num5] : null);
			string text2 = ((num5 < array2.Length) ? array2[num5] : null);
			if (text == text2)
			{
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder5 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(2, 1, stringBuilder2);
				handler.AppendLiteral("  ");
				handler.AppendFormatted(text);
				stringBuilder5.AppendLine(ref handler);
				num3++;
				continue;
			}
			if (text != null && !hashSet2.Contains(text))
			{
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder6 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(2, 1, stringBuilder2);
				handler.AppendLiteral("- ");
				handler.AppendFormatted(text);
				stringBuilder6.AppendLine(ref handler);
				num2++;
			}
			if (text2 != null && !hashSet.Contains(text2))
			{
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder7 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(2, 1, stringBuilder2);
				handler.AppendLiteral("+ ");
				handler.AppendFormatted(text2);
				stringBuilder7.AppendLine(ref handler);
				num++;
			}
			if (text != null && hashSet2.Contains(text) && text != text2)
			{
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder8 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(2, 1, stringBuilder2);
				handler.AppendLiteral("  ");
				handler.AppendFormatted(text);
				stringBuilder8.AppendLine(ref handler);
				num3++;
			}
		}
		return new DiffResult(stringBuilder.ToString(), num, num2, num3);
	}
}
