using EonaCat.Json;
using System;
using System.Collections;
using System.Diagnostics;

namespace EonaCat.LogStack.Extensions;

// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.

public static class ExceptionExtensions
{
    public static string FormatExceptionToMessage(this Exception exception, string module = null, string method = null)
    {
        if (exception == null)
        {
            return string.Empty;
        }

        var st = new StackTrace(exception, true);
        var frame = st.GetFrame(0);
        int fileLine = -1;
        string filename = "Unknown";

        if (frame != null)
        {
            fileLine = frame.GetFileLineNumber();
            filename = frame.GetFileName();
        }

        var sb = new StringBuilderChill();

        sb.AppendLine();
        sb.AppendLine($"--- Exception details provided by {DllInfo.ApplicationName} on {Environment.MachineName} ---");
        if (!string.IsNullOrEmpty(module))
        {
            sb.AppendLine("  Module     : " + module);
        }

        if (!string.IsNullOrEmpty(method))
        {
            sb.AppendLine("  Method     : " + method);
        }

        sb.Append("  Type       : ").AppendLine(exception.GetType().ToString());
        sb.Append("  Data       : ").AppendLine(exception.Data != null && exception.Data.Count > 0
            ? FormatExceptionData(exception.Data)
            : "(none)");
        sb.Append("  Inner      : ").AppendLine(exception.InnerException != null
            ? FormatInnerException(exception.InnerException)
            : "(null)");
        sb.Append("  Message    : ").AppendLine(exception.Message);
        sb.Append("  Source     : ").AppendLine(exception.Source);
        sb.Append("  StackTrace : ").AppendLine(exception.StackTrace);
        sb.Append("  Line       : ").AppendLine(fileLine.ToString());
        sb.Append("  File       : ").AppendLine(filename);
        sb.Append("  ToString   : ").AppendLine(exception.ToString());
        sb.AppendLine("---");

        return sb.ToString();
    }

    private static string FormatExceptionData(IDictionary data)
    {
        var sb = new StringBuilderChill();

        foreach (DictionaryEntry entry in data)
        {
            if (entry.Key != null)
            {
                sb.Append("  | ")
                .Append(entry.Key);
            }

            if (entry.Value != null)
            {
                sb.Append(": ")
                .AppendLine(entry.Value.ToString());
            }
        }

        return sb.ToString();
    }

    private static string FormatInnerException(Exception innerException)
    {
        var sb = new StringBuilderChill();

        sb.AppendLine(innerException.GetType().ToString())
            .AppendLine("    Message    : " + innerException.Message)
            .AppendLine("    Source     : " + innerException.Source)
            .AppendLine("    StackTrace : " + innerException.StackTrace)
            .AppendLine("    ToString   : " + innerException)
            .Append("    Data       : ")
            .AppendLine(innerException.Data != null && innerException.Data.Count > 0
                ? FormatExceptionData(innerException.Data)
                : "(none)");

        return sb.ToString();
    }
}