using e_suite.Database.Audit.Models;
using e_suite.Database.Audit.Tables.Audit;
using System.ComponentModel;

namespace e_suite.API.Common.models;

public class AuditLogEntry : IId
{
    public AuditLogEntry()
    {

    }

    public AuditLogEntry(AuditEntry auditEntry)
    {

        Id = auditEntry.Id;
        UserId = auditEntry.AuditLog.UserId;
        UserDisplayName = auditEntry.AuditLog.UserDisplayName;
        Type = auditEntry.AuditLog.Type;
        DateTime = auditEntry.AuditLog.DateTime;
        Fields = auditEntry.AuditLog.Fields;
        Comment = auditEntry.AuditLog.Comment;
        EntityName = auditEntry.EntityName;
        EntityDisplayName = GetDisplayNameForClass(auditEntry.EntityName);
        PrimaryKey = auditEntry.PrimaryKey;
        DisplayName = auditEntry.DisplayName ?? string.Empty;
    }

    private string GetDisplayNameForClass(string entityName)
    {
        var type = GetTypeFromFullName(entityName);

        if (type != null)
        {
            var displayName = GetDisplayName(type);
            if (displayName != null)
                return displayName;

            return type.Name;
        }

        return entityName;
    }

    private readonly Dictionary<string, Type> cacheDictionary = new();

    private Type? GetTypeFromFullName(string className)
    {
        if (cacheDictionary.TryGetValue(className, out var name))
            return name;

        foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            foreach (var type in assembly.GetTypes())
            {
                if (type.FullName == null ||
                    !type.FullName.Equals(className, StringComparison.OrdinalIgnoreCase))
                    continue;

                cacheDictionary.Add(className, type);
                return type;
            }
        }

        return null;
    }

    private static string? GetDisplayName(Type type)
    {
        return (from attribute in type.CustomAttributes where attribute.AttributeType == typeof(DisplayNameAttribute) select attribute.ConstructorArguments[0].ToString().Trim('"')).FirstOrDefault();
    }

    public long Id { get; set; }
        
    public long UserId { get; set; }
    public string UserDisplayName { get; set; } = string.Empty;
        
    public string Type { get; set; } = string.Empty;

    public DateTimeOffset DateTime { get; set; }

    public string Fields { get; set; } = string.Empty;

    public string Comment { get; set; } = string.Empty;

    public string EntityName { get; set; } = string.Empty;

    public string PrimaryKey { get; set; } = string.Empty;

    public string EntityDisplayName { get; set; } = string.Empty;

    public string DisplayName { get; set; } = string.Empty;
}