using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Security;
using System.Text;

namespace Kit.Helpers
{

    public static class ExceptionHelper_Extensions
    {
        public static string GetInfoAsPlainText(this Exception ex)
        {
            if (ex == null) return string.Empty;
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("Source: {0}", ex.Source); sb.AppendLine();
            sb.AppendFormat("Message: {0}", ex.Message); sb.AppendLine();
            sb.AppendFormat("StackTrace: {0}", ex.StackTrace); sb.AppendLine();
            if (ex.InnerException != null)
            {
                sb.AppendLine("InnerException:");
                sb.Append(ex.InnerException.GetInfoAsPlainText());
            }

            return sb.ToString();
        }

        public static string GetInfoAsHtml(this Exception ex)
        {
            return ex.GetInfoAsPlainText().Replace(Environment.NewLine, "<br />");
        }
    }

    public static class ExceptionExtensions
    {
        public static string ToString(this Exception exception, ExceptionToStringSettings settings)
        {
            Exception ex = exception;

            var stringBuilder = new StringBuilder();

            if (ExceptionToStringSettings.ShowMessageAndInnerExceptionMessages == (ExceptionToStringSettings.ShowMessageAndInnerExceptionMessages & settings))
            {
                if (ExceptionToStringSettings.ShowSeparators == (ExceptionToStringSettings.ShowSeparators & settings))
                {
                    stringBuilder.AppendLine();
                    stringBuilder.AppendLine("*********************** Exception Text ************************");
                }

                stringBuilder.Append(ex);
            }

            if (ExceptionToStringSettings.ShowAssemblyInformation == (ExceptionToStringSettings.ShowAssemblyInformation & settings))
            {
                if (ExceptionToStringSettings.ShowSeparators == (ExceptionToStringSettings.ShowSeparators & settings))
                {
                    stringBuilder.AppendLine();
                    stringBuilder.AppendLine();
                    stringBuilder.AppendLine();
                    stringBuilder.AppendLine("********************** Loaded Assemblies **********************");
                }

                stringBuilder.Append(GetLoadedAssemblyInfo());

            }

            return stringBuilder.ToString();
        }

        private static string GetLoadedAssemblyInfo()
        {
            const string separator = "--------------------------------------------------------------";

            //new FileIOPermission(PermissionState.Unrestricted).Assert();
            try
            {
                var stringBuilder = new StringBuilder();

                Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
                foreach (Assembly assembly in assemblies)
                {
                    AssemblyName name2 = assembly.GetName();
                    string text2 = string.Empty;

                    try
                    {
                        if (!string.IsNullOrEmpty(name2.EscapedCodeBase))
                        {
                            var uri = new Uri(name2.EscapedCodeBase);
                            if (uri.Scheme == "file")
                            {
                                text2 = FileVersionInfo.GetVersionInfo(GetLocalPath(name2.EscapedCodeBase)).FileVersion;
                            }
                        }
                    }
                    catch (FileNotFoundException)
                    {
                    }

                    stringBuilder.AppendLine(name2.Name);
                    stringBuilder.AppendLine(name2.Version.ToString());
                    stringBuilder.AppendLine(text2);
                    stringBuilder.AppendLine(name2.EscapedCodeBase);
                    stringBuilder.Append(separator);
                    stringBuilder.AppendLine();
                }

                return stringBuilder.ToString();
            }
            finally
            {
                // TODO: разобраться, что это. В .NET Core 6 признано небезопасным. подключается как <PackageReference Include="System.Security.Permissions" Version="7.0.0" />
                //CodeAccessPermission.RevertAssert();
            }
        }

        private static string GetLocalPath(string fileName)
        {
            var uri = new Uri(fileName);
            return uri.LocalPath + uri.Fragment;
        }
    }

    /// <summary>
    /// Settings for <see cref="ExceptionExtensions.ToString(System.Exception, ExceptionToStringSettings)"/>
    /// </summary>
    [Flags]
    public enum ExceptionToStringSettings
    {
        /// <summary>
        /// Show message
        /// </summary>
        ShowMessageAndInnerExceptionMessages = 1,

        /// <summary>
        /// Show assembly information
        /// </summary>
        ShowAssemblyInformation = 2,

        /// <summary>
        /// Show sepparators
        /// </summary>
        ShowSeparators = 4,

        //All
        All = ShowMessageAndInnerExceptionMessages | ShowAssemblyInformation | ShowSeparators
    }
}