using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace VCommon.Diagnostics
{
    public static class StackTraceExtensionMethod
    {
        /// <summary> 将堆栈跟踪信息格式化成每一帧都带程序集的详情文本, 可指定一个type来忽略之上的调用堆栈帧 </summary>
        public static string GetFormattedDetailStackTraceText(this StackTrace me, Type skipUpper = null, bool hasSourceStackFrameOnly = false)
        {
            var rawFrames = me.GetFrames();
            if (null == rawFrames) return null;

            var upperFrames = rawFrames;

            if (null != skipUpper)
            {
                var lst = new List<StackFrame>(rawFrames.Length);
                for (var i = rawFrames.Length - 1; i >= 0; i--)
                {
                    if (rawFrames[i].GetMethod().DeclaringType == skipUpper) break;
                    lst.Insert(0, rawFrames[i]);
                }
                upperFrames = lst.ToArray();
            }

            var sb = new StringBuilder();

            var filteredFrames = upperFrames;

            if (hasSourceStackFrameOnly)
            {
                filteredFrames = upperFrames.Where(p => p.HasSource()).ToArray();
            }

            foreach (var frame in filteredFrames)
            {
                var method = frame.GetMethod();
                var type = method.DeclaringType;
                var asm = type?.Assembly;
                var filename = frame.GetFileName();

                if (null != asm) sb.Append($"[{asm.GetName().Name}] ");
                if (null != type) sb.Append($"{type.FullName}::");
                sb.Append($"{method}");
                if (null != filename) sb.Append($" @ {filename}:{frame.GetFileLineNumber()},{frame.GetFileColumnNumber()}");

                sb.AppendLine();
            }

            return sb.ToString();
        }
    }
}
