using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using AxCopilot.SDK;

namespace AxCopilot.Handlers;

public class ColorHandler : IActionHandler
{
	private static readonly Dictionary<string, string> _namedColors = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
	{
		["red"] = "#FF0000",
		["빨강"] = "#FF0000",
		["빨간색"] = "#FF0000",
		["green"] = "#008000",
		["초록"] = "#008000",
		["초록색"] = "#008000",
		["blue"] = "#0000FF",
		["파랑"] = "#0000FF",
		["파란색"] = "#0000FF",
		["white"] = "#FFFFFF",
		["흰색"] = "#FFFFFF",
		["하양"] = "#FFFFFF",
		["black"] = "#000000",
		["검정"] = "#000000",
		["검은색"] = "#000000",
		["yellow"] = "#FFFF00",
		["노랑"] = "#FFFF00",
		["노란색"] = "#FFFF00",
		["orange"] = "#FFA500",
		["주황"] = "#FFA500",
		["주황색"] = "#FFA500",
		["purple"] = "#800080",
		["보라"] = "#800080",
		["보라색"] = "#800080",
		["pink"] = "#FFC0CB",
		["분홍"] = "#FFC0CB",
		["분홍색"] = "#FFC0CB",
		["hotpink"] = "#FF69B4",
		["핫핑크"] = "#FF69B4",
		["cyan"] = "#00FFFF",
		["시안"] = "#00FFFF",
		["magenta"] = "#FF00FF",
		["마젠타"] = "#FF00FF",
		["brown"] = "#A52A2A",
		["갈색"] = "#A52A2A",
		["gray"] = "#808080",
		["grey"] = "#808080",
		["회색"] = "#808080",
		["회"] = "#808080",
		["silver"] = "#C0C0C0",
		["은색"] = "#C0C0C0",
		["gold"] = "#FFD700",
		["금색"] = "#FFD700",
		["navy"] = "#000080",
		["남색"] = "#000080",
		["teal"] = "#008080",
		["틸"] = "#008080",
		["lime"] = "#00FF00",
		["라임"] = "#00FF00",
		["maroon"] = "#800000",
		["밤색"] = "#800000",
		["olive"] = "#808000",
		["올리브"] = "#808000",
		["coral"] = "#FF7F50",
		["코랄"] = "#FF7F50",
		["salmon"] = "#FA8072",
		["연어색"] = "#FA8072",
		["skyblue"] = "#87CEEB",
		["하늘색"] = "#87CEEB",
		["lightblue"] = "#ADD8E6",
		["연파랑"] = "#ADD8E6",
		["darkblue"] = "#00008B",
		["진파랑"] = "#00008B",
		["darkgreen"] = "#006400",
		["진초록"] = "#006400",
		["lightgreen"] = "#90EE90",
		["연초록"] = "#90EE90",
		["indigo"] = "#4B0082",
		["인디고"] = "#4B0082",
		["violet"] = "#EE82EE",
		["바이올렛"] = "#EE82EE",
		["beige"] = "#F5F5DC",
		["베이지"] = "#F5F5DC",
		["ivory"] = "#FFFFF0",
		["아이보리"] = "#FFFFF0",
		["khaki"] = "#F0E68C",
		["카키"] = "#F0E68C",
		["lavender"] = "#E6E6FA",
		["라벤더"] = "#E6E6FA",
		["turquoise"] = "#40E0D0",
		["터키옥"] = "#40E0D0",
		["chocolate"] = "#D2691E",
		["초콜릿"] = "#D2691E",
		["crimson"] = "#DC143C",
		["크림슨"] = "#DC143C",
		["transparent"] = "#00000000"
	};

	private static readonly Regex _hexRe = new Regex("^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$");

	private static readonly Regex _rgbRe = new Regex("^(?:rgb\\s*\\()?\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*\\)?$", RegexOptions.IgnoreCase);

	private static readonly Regex _rgbaRe = new Regex("^rgba\\s*\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*([\\d.]+)\\s*\\)$", RegexOptions.IgnoreCase);

	private static readonly Regex _hslRe = new Regex("^hsl\\s*\\(\\s*([\\d.]+)\\s*,\\s*([\\d.]+)%?\\s*,\\s*([\\d.]+)%?\\s*\\)$", RegexOptions.IgnoreCase);

	public string? Prefix => "color";

	public PluginMetadata Metadata => new PluginMetadata("Color", "색상 변환기 — color #FF5500 · color 255,85,0 · color red", "1.0", "AX");

	public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
	{
		if (string.IsNullOrWhiteSpace(query))
		{
			return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("색상 코드를 입력하세요", "예: #FF5500  ·  255,85,0  ·  red  ·  hsl(20,100%,50%)", null, null, null, "\ue771")));
		}
		string text = query.Trim();
		List<LauncherItem> list = new List<LauncherItem>();
		if (_hexRe.IsMatch(text))
		{
			string text2 = text.TrimStart('#');
			if (text2.Length == 3)
			{
				text2 = $"{text2[0]}{text2[0]}{text2[1]}{text2[1]}{text2[2]}{text2[2]}";
			}
			byte a = byte.MaxValue;
			int r;
			int g;
			int b;
			if (text2.Length == 8)
			{
				a = Convert.ToByte(text2.Substring(0, 2), 16);
				r = Convert.ToInt32(text2.Substring(2, 2), 16);
				g = Convert.ToInt32(text2.Substring(4, 2), 16);
				b = Convert.ToInt32(text2.Substring(6, 2), 16);
			}
			else
			{
				r = Convert.ToInt32(text2.Substring(0, 2), 16);
				g = Convert.ToInt32(text2.Substring(2, 2), 16);
				b = Convert.ToInt32(text2.Substring(4, 2), 16);
			}
			AddColorItems(list, r, g, b, a, "#" + text2.ToUpperInvariant());
			return Task.FromResult((IEnumerable<LauncherItem>)list);
		}
		Match match = _rgbRe.Match(text);
		if (match.Success)
		{
			int num = int.Parse(match.Groups[1].Value);
			int num2 = int.Parse(match.Groups[2].Value);
			int num3 = int.Parse(match.Groups[3].Value);
			if (num <= 255 && num2 <= 255 && num3 <= 255)
			{
				AddColorItems(list, num, num2, num3, byte.MaxValue, $"rgb({num},{num2},{num3})");
				return Task.FromResult((IEnumerable<LauncherItem>)list);
			}
		}
		Match match2 = _rgbaRe.Match(text);
		if (match2.Success)
		{
			int num4 = int.Parse(match2.Groups[1].Value);
			int num5 = int.Parse(match2.Groups[2].Value);
			int num6 = int.Parse(match2.Groups[3].Value);
			double num7 = double.Parse(match2.Groups[4].Value, CultureInfo.InvariantCulture);
			byte a2 = (byte)Math.Clamp((int)(num7 * 255.0), 0, 255);
			if (num4 <= 255 && num5 <= 255 && num6 <= 255)
			{
				AddColorItems(list, num4, num5, num6, a2, $"rgba({num4},{num5},{num6},{num7:G3})");
				return Task.FromResult((IEnumerable<LauncherItem>)list);
			}
		}
		Match match3 = _hslRe.Match(text);
		if (match3.Success)
		{
			double num8 = double.Parse(match3.Groups[1].Value, CultureInfo.InvariantCulture);
			double num9 = double.Parse(match3.Groups[2].Value, CultureInfo.InvariantCulture) / 100.0;
			double num10 = double.Parse(match3.Groups[3].Value, CultureInfo.InvariantCulture) / 100.0;
			var (r2, g2, b2) = HslToRgb(num8, num9, num10);
			AddColorItems(list, r2, g2, b2, byte.MaxValue, $"hsl({num8:G},{num9 * 100.0:G}%,{num10 * 100.0:G}%)");
			return Task.FromResult((IEnumerable<LauncherItem>)list);
		}
		if (_namedColors.TryGetValue(text, out string value))
		{
			string text3 = value.TrimStart('#');
			int r3 = Convert.ToInt32(text3.Substring(0, 2), 16);
			int g3 = Convert.ToInt32(text3.Substring(2, 2), 16);
			int b3 = Convert.ToInt32(text3.Substring(4, 2), 16);
			AddColorItems(list, r3, g3, b3, byte.MaxValue, value.ToUpperInvariant());
			return Task.FromResult((IEnumerable<LauncherItem>)list);
		}
		string searchQ = text.ToLowerInvariant();
		IEnumerable<KeyValuePair<string, string>> enumerable = _namedColors.Where<KeyValuePair<string, string>>((KeyValuePair<string, string> kv) => kv.Key.Contains(searchQ, StringComparison.OrdinalIgnoreCase)).Take(8);
		foreach (KeyValuePair<string, string> item in enumerable)
		{
			list.Add(new LauncherItem(item.Key + "  →  " + item.Value.ToUpperInvariant(), "Enter로 HEX 복사", null, item.Value.ToUpperInvariant(), null, "\ue771"));
		}
		if (!list.Any())
		{
			list.Add(new LauncherItem("인식할 수 없는 색상", "#RRGGBB · RGB(r,g,b) · hsl(h,s%,l%) · red 등 색상 이름", null, null, null, "\uea39"));
		}
		return Task.FromResult((IEnumerable<LauncherItem>)list);
	}

	public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
	{
		if (item.Data is string text)
		{
			try
			{
				Clipboard.SetText(text);
			}
			catch
			{
			}
		}
		return Task.CompletedTask;
	}

	private static void AddColorItems(List<LauncherItem> items, int r, int g, int b, byte a, string source)
	{
		string text = ((a == byte.MaxValue) ? $"#{r:X2}{g:X2}{b:X2}" : $"#{a:X2}{r:X2}{g:X2}{b:X2}");
		string text2 = ((a == byte.MaxValue) ? $"rgb({r}, {g}, {b})" : $"rgba({r}, {g}, {b}, {(double)(int)a / 255.0:G3})");
		(double h, double s, double l) tuple = RgbToHsl(r, g, b);
		double item = tuple.h;
		double item2 = tuple.s;
		double item3 = tuple.l;
		string text3 = $"hsl({item:G3}, {item2 * 100.0:G3}%, {item3 * 100.0:G3}%)";
		(double h, double s, double v) tuple2 = RgbToHsv(r, g, b);
		double item4 = tuple2.h;
		double item5 = tuple2.s;
		double item6 = tuple2.v;
		string text4 = $"hsv({item4:G3}, {item5 * 100.0:G3}%, {item6 * 100.0:G3}%)";
		items.Add(new LauncherItem("HEX  →  " + text.ToUpperInvariant(), source + "  ·  Enter로 복사", null, text.ToUpperInvariant(), null, "\ue771"));
		items.Add(new LauncherItem("RGB  →  " + text2, source + "  ·  Enter로 복사", null, text2, null, "\ue771"));
		items.Add(new LauncherItem("HSL  →  " + text3, source + "  ·  Enter로 복사", null, text3, null, "\ue771"));
		items.Add(new LauncherItem("HSV  →  " + text4, source + "  ·  Enter로 복사", null, text4, null, "\ue771"));
	}

	private static (double h, double s, double l) RgbToHsl(int r, int g, int b)
	{
		double num = (double)r / 255.0;
		double num2 = (double)g / 255.0;
		double num3 = (double)b / 255.0;
		double num4 = Math.Max(num, Math.Max(num2, num3));
		double num5 = Math.Min(num, Math.Min(num2, num3));
		double num6 = (num4 + num5) / 2.0;
		double num7 = 0.0;
		double value = 0.0;
		if (num4 != num5)
		{
			double num8 = num4 - num5;
			value = ((num6 > 0.5) ? (num8 / (2.0 - num4 - num5)) : (num8 / (num4 + num5)));
			num7 = ((num4 == num) ? ((num2 - num3) / num8 + (double)((num2 < num3) ? 6 : 0)) : ((num4 == num2) ? ((num3 - num) / num8 + 2.0) : ((num - num2) / num8 + 4.0)));
			num7 /= 6.0;
		}
		return (h: Math.Round(num7 * 360.0, 1), s: Math.Round(value, 4), l: Math.Round(num6, 4));
	}

	private static (double h, double s, double v) RgbToHsv(int r, int g, int b)
	{
		double num = (double)r / 255.0;
		double num2 = (double)g / 255.0;
		double num3 = (double)b / 255.0;
		double num4 = Math.Max(num, Math.Max(num2, num3));
		double num5 = Math.Min(num, Math.Min(num2, num3));
		double value = num4;
		double value2 = 0.0;
		double num6 = 0.0;
		double num7 = num4 - num5;
		if (num4 != 0.0)
		{
			value2 = num7 / num4;
		}
		if (num7 != 0.0)
		{
			num6 = ((num4 == num) ? ((num2 - num3) / num7 + (double)((num2 < num3) ? 6 : 0)) : ((num4 == num2) ? ((num3 - num) / num7 + 2.0) : ((num - num2) / num7 + 4.0)));
			num6 /= 6.0;
		}
		return (h: Math.Round(num6 * 360.0, 1), s: Math.Round(value2, 4), v: Math.Round(value, 4));
	}

	private static (int r, int g, int b) HslToRgb(double h, double s, double l)
	{
		double num;
		double num2;
		double num3;
		if (s == 0.0)
		{
			num = (num2 = (num3 = l));
		}
		else
		{
			double num4 = ((l < 0.5) ? (l * (1.0 + s)) : (l + s - l * s));
			double p = 2.0 * l - num4;
			h /= 360.0;
			num = Hue2Rgb(p, num4, h + 1.0 / 3.0);
			num2 = Hue2Rgb(p, num4, h);
			num3 = Hue2Rgb(p, num4, h - 1.0 / 3.0);
		}
		return (r: (int)Math.Round(num * 255.0), g: (int)Math.Round(num2 * 255.0), b: (int)Math.Round(num3 * 255.0));
	}

	private static double Hue2Rgb(double p, double q, double t)
	{
		if (t < 0.0)
		{
			t += 1.0;
		}
		if (t > 1.0)
		{
			t -= 1.0;
		}
		if (t < 1.0 / 6.0)
		{
			return p + (q - p) * 6.0 * t;
		}
		if (t < 0.5)
		{
			return q;
		}
		if (t < 2.0 / 3.0)
		{
			return p + (q - p) * (2.0 / 3.0 - t) * 6.0;
		}
		return p;
	}
}
