using System.Reflection;
using static AyCode.Core.Helpers.JsonUtilities;

namespace AyCode.Core.Serializers.Toons;

public static partial class AcToonSerializer
{
    /// <summary>
    /// Convention: Property named "Id" or "{TypeName}Id" is a primary key.
    /// </summary>
    private static bool IsConventionPrimaryKey(PropertyInfo property)
    {
        if (property.PropertyType != typeof(int) &&
            property.PropertyType != typeof(long) &&
            property.PropertyType != typeof(Guid))
        {
            return false;
        }

        return property.Name.Equals("Id", StringComparison.OrdinalIgnoreCase) ||
               property.Name.Equals(property.DeclaringType?.Name + "Id", StringComparison.OrdinalIgnoreCase);
    }

    /// <summary>
    /// Check if a type has a primary key property.
    /// First checks for IsPrimaryKey=true in ToonDescription, then falls back to "Id" property.
    /// </summary>
    private static bool HasPrimaryKeyProperty(Type type)
    {
        if (IsPrimitiveOrStringFast(type))
        {
            return false;
        }

        var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);

        // First: check for ToonDescription with IsPrimaryKey = true
        foreach (var prop in properties)
        {
            var customDescription = prop.GetCustomAttribute<ToonDescriptionAttribute>();
            if (customDescription?.IsPrimaryKey == true)
            {
                return true;
            }
        }

        // Fallback: check for "Id" or "{TypeName}Id" property
        foreach (var prop in properties)
        {
            if (prop.Name.Equals("Id", StringComparison.OrdinalIgnoreCase) ||
                prop.Name.Equals(type.Name + "Id", StringComparison.OrdinalIgnoreCase))
            {
                // Must be a value type (int, long, Guid, etc.)
                if (prop.PropertyType.IsValueType)
                {
                    return true;
                }
            }
        }

        return false;
    }

    /// <summary>
    /// Check if two types match (handles different Type instances from different assemblies).
    /// </summary>
    private static bool IsTypeMatch(Type? type1, Type? type2)
    {
        if (type1 == null || type2 == null) return false;
        return type1 == type2 || type2.IsAssignableFrom(type1) || type1.FullName == type2.FullName;
    }
}
