using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Diagnostics;
using System.Xml;

namespace DocGenerator
{
    internal class Program
    {
        internal class CommentBlock
        {
            public string MethodComment { get; set; } = string.Empty;
            public Dictionary<string, string> ParametersComment { get; set; } = new Dictionary<string, string>();
            public string ReturnComment { get; set; } = string.Empty;
        }

        private static CommentBlock ParseComment(string comment)
        {
            CommentBlock block = new();

            string newComment = "<root>\n" +  comment.Replace("///", "") + "</root>";

            XmlDocument? xmlDoc = new();
            try
            {
                xmlDoc.LoadXml(newComment);
            }
            catch
            {
                return block;
            }

            XmlNode? summaryNode = xmlDoc.SelectSingleNode("//summary");
            string? methodSummary = summaryNode?.InnerText.Trim();

            XmlNodeList? paramNodes = xmlDoc.SelectNodes("//param");
            if (paramNodes != null)
            {
                foreach (XmlNode paramNode in paramNodes)
                {
                    string? paramName = paramNode?.Attributes?["name"]?.Value;
                    string? paramDescription = paramNode?.InnerText.Trim();
                    if (paramName != null)
                    {
                        if (block.ParametersComment.ContainsKey(paramName))
                        {
                            block.ParametersComment[paramName] = paramDescription ?? "";
                        }
                        else
                        {
                            block.ParametersComment.Add(paramName, paramDescription ?? "");
                        }
                    }
                }
            }

            XmlNode? returnsNode = xmlDoc.SelectSingleNode("//returns");
            string? returnsDescription = returnsNode?.InnerText.Trim();

            block.MethodComment = methodSummary ?? "";
            block.ReturnComment = returnsDescription ?? "";

            return block;
        }

        private static void ParseClass(ClassDeclarationSyntax classDeclaration)
        {
            string className = classDeclaration.Identifier.ValueText;
            Directory.CreateDirectory(className);

            var methodDeclarations = classDeclaration.Members.OfType<MethodDeclarationSyntax>();
            foreach (MethodDeclarationSyntax methodDeclaration in methodDeclarations)
            {
                // 忽略非 public 方法
                if (methodDeclaration.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.PublicKeyword)))
                {
                    string methodName = methodDeclaration.Identifier.ValueText;
                    string ReturnType = methodDeclaration.ReturnType.ToString();

                    // 忽略点击事件
                    if (methodName.EndsWith("Click"))
                    {
                        continue;
                    }

                    // 获取注释
                    string comment = methodDeclaration.GetLeadingTrivia().ToString();
                    CommentBlock commentBlock = ParseComment(comment);

                    using var streamerWriter = File.CreateText(Path.Combine(className, $"{methodName}.md"));

                    streamerWriter.WriteLine($"# {methodName}\n");

                    streamerWriter.WriteLine("## 定义\n");
                    streamerWriter.WriteLine(commentBlock.MethodComment + "\n");

                    /// 方法原型
                    streamerWriter.WriteLine("```CSharp");
                    streamerWriter.WriteLine(methodDeclaration.ToString().Split("\n")[0]);
                    streamerWriter.WriteLine("```");

                    streamerWriter.WriteLine();

                    streamerWriter.WriteLine("## 请求参数\n");

                    if (methodDeclaration.ParameterList.Parameters.Count > 0)
                    {
                        streamerWriter.WriteLine("| 参数 | 类型 | 约束 | 说明 |");
                        streamerWriter.WriteLine("| - | - | - | - |");
                    }

                    foreach (var parameter in methodDeclaration.ParameterList.Parameters)
                    {
                        var paramName = parameter.Identifier.ValueText;
                        var paramType = parameter.Type.ToString();
                        var desc = string.Empty;
                        if (commentBlock.ParametersComment.ContainsKey(paramName))
                        {
                            desc = commentBlock.ParametersComment[paramName];
                        }

                        streamerWriter.WriteLine($"| {paramName} | {paramType} |  | {desc} |");
                    }
                    streamerWriter.WriteLine("\n");

                    streamerWriter.WriteLine("## 返回\n");
                    streamerWriter.WriteLine($"类型: {ReturnType}");
                    streamerWriter.WriteLine(commentBlock.ReturnComment);
                    streamerWriter.WriteLine("\n");

                    streamerWriter.WriteLine("## 请求示例\n");
                    streamerWriter.WriteLine("## 错误处理\n");
                    streamerWriter.WriteLine("## 注意事项\n");
                }
            }
        }

        private static void ParseFile(string filePath)
        {
            string code = File.ReadAllText(filePath);
            SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);
            CompilationUnitSyntax root = syntaxTree.GetCompilationUnitRoot();

            var classDeclarations = root.Members.OfType<NamespaceDeclarationSyntax>()
                .SelectMany(namespaceDeclaration => namespaceDeclaration.Members)
                .OfType<ClassDeclarationSyntax>();

            foreach (var classDeclaration in classDeclarations)
            {
                ParseClass(classDeclaration);
            }
        }

        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine($"Usage: {Process.GetCurrentProcess().ProcessName} <xxx.cs>");
                return;
            }

            ParseFile(@"D:\project\Drawer\Drawer\UCDraw\UCDraw\UC\MainView.cs");
        }
    }
}