using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace AxCopilot.Services.Agent;

public static class ProjectRulesService
{
	public class ProjectRule
	{
		public string FilePath { get; set; } = "";

		public string Name { get; set; } = "";

		public string Description { get; set; } = "";

		public string AppliesTo { get; set; } = "";

		public string When { get; set; } = "always";

		public string Body { get; set; } = "";
	}

	private static readonly Regex FrontMatterRegex = new Regex("^---\\s*\\n(.*?)\\n---\\s*\\n", RegexOptions.Compiled | RegexOptions.Singleline);

	private static readonly Regex YamlKeyValue = new Regex("^\\s*(\\w[\\w-]*)\\s*:\\s*(.+?)\\s*$", RegexOptions.Multiline | RegexOptions.Compiled);

	public static List<ProjectRule> LoadRules(string workFolder)
	{
		List<ProjectRule> list = new List<ProjectRule>();
		if (string.IsNullOrEmpty(workFolder))
		{
			return list;
		}
		string text = FindRulesDirectory(workFolder);
		if (text == null)
		{
			return list;
		}
		try
		{
			string[] files = Directory.GetFiles(text, "*.md");
			foreach (string filePath in files)
			{
				ProjectRule projectRule = ParseRuleFile(filePath);
				if (projectRule != null)
				{
					list.Add(projectRule);
				}
			}
		}
		catch
		{
		}
		return list;
	}

	public static List<ProjectRule> FilterRules(List<ProjectRule> rules, string when = "always", IEnumerable<string>? filePaths = null)
	{
		List<ProjectRule> list = new List<ProjectRule>();
		foreach (ProjectRule rule in rules)
		{
			string text = rule.When.ToLowerInvariant().Trim();
			if (text != "always" && text != when.ToLowerInvariant())
			{
				continue;
			}
			if (!string.IsNullOrEmpty(rule.AppliesTo) && filePaths != null)
			{
				string pattern = rule.AppliesTo.Trim();
				if (!filePaths.Any((string fp) => MatchesGlob(fp, pattern)))
				{
					continue;
				}
			}
			list.Add(rule);
		}
		return list;
	}

	public static string FormatForSystemPrompt(List<ProjectRule> rules)
	{
		if (rules.Count == 0)
		{
			return "";
		}
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.AppendLine("\n## 프로젝트 규칙 (.ax/rules/)");
		stringBuilder.AppendLine("아래 규칙을 반드시 준수하세요:\n");
		foreach (ProjectRule rule in rules)
		{
			if (!string.IsNullOrEmpty(rule.Name))
			{
				StringBuilder stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder3 = stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(4, 1, stringBuilder2);
				handler.AppendLiteral("### ");
				handler.AppendFormatted(rule.Name);
				stringBuilder3.AppendLine(ref handler);
			}
			if (!string.IsNullOrEmpty(rule.Description))
			{
				StringBuilder stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder4 = stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(3, 1, stringBuilder2);
				handler.AppendLiteral("*");
				handler.AppendFormatted(rule.Description);
				handler.AppendLiteral("*\n");
				stringBuilder4.AppendLine(ref handler);
			}
			stringBuilder.AppendLine(rule.Body.Trim());
			stringBuilder.AppendLine();
		}
		return stringBuilder.ToString();
	}

	internal static string? FindRulesDirectory(string workFolder)
	{
		string text = workFolder;
		for (int i = 0; i < 3; i++)
		{
			if (string.IsNullOrEmpty(text))
			{
				break;
			}
			string text2 = Path.Combine(text, ".ax", "rules");
			if (Directory.Exists(text2))
			{
				return text2;
			}
			text = Directory.GetParent(text)?.FullName;
		}
		return null;
	}

	internal static ProjectRule? ParseRuleFile(string filePath)
	{
		try
		{
			string text = File.ReadAllText(filePath, Encoding.UTF8);
			if (string.IsNullOrWhiteSpace(text))
			{
				return null;
			}
			ProjectRule projectRule = new ProjectRule
			{
				FilePath = filePath,
				Name = Path.GetFileNameWithoutExtension(filePath)
			};
			Match match = FrontMatterRegex.Match(text);
			if (match.Success)
			{
				string value = match.Groups[1].Value;
				foreach (Match item in YamlKeyValue.Matches(value))
				{
					string text2 = item.Groups[1].Value.ToLowerInvariant();
					string text3 = item.Groups[2].Value.Trim().Trim('"', '\'');
					switch (text2)
					{
					case "name":
						projectRule.Name = text3;
						break;
					case "description":
						projectRule.Description = text3;
						break;
					case "applies-to":
					case "appliesto":
						projectRule.AppliesTo = text3;
						break;
					case "when":
						projectRule.When = text3;
						break;
					}
				}
				string text4 = text;
				int num = match.Index + match.Length;
				projectRule.Body = text4.Substring(num, text4.Length - num);
			}
			else
			{
				projectRule.Body = text;
			}
			return string.IsNullOrWhiteSpace(projectRule.Body) ? null : projectRule;
		}
		catch
		{
			return null;
		}
	}

	private static bool MatchesGlob(string path, string pattern)
	{
		if (pattern.StartsWith("*."))
		{
			string text = pattern;
			return path.EndsWith(text.Substring(1, text.Length - 1), StringComparison.OrdinalIgnoreCase);
		}
		if (pattern.StartsWith("**/"))
		{
			string text = pattern;
			string pattern2 = text.Substring(3, text.Length - 3);
			return MatchesGlob(Path.GetFileName(path), pattern2);
		}
		return Path.GetFileName(path).Equals(pattern, StringComparison.OrdinalIgnoreCase);
	}
}
