using System.Collections.Generic;
using System.Linq;

namespace ZB.MOM.WW.CBDD.SourceGenerators.Models
{
    /// <summary>
    /// Contains metadata describing an entity discovered by source generation.
    /// </summary>
    public class EntityInfo
    {
        /// <summary>
        /// Gets or sets the entity name.
        /// </summary>
        public string Name { get; set; } = "";
        /// <summary>
        /// Gets or sets the entity namespace.
        /// </summary>
        public string Namespace { get; set; } = "";
        /// <summary>
        /// Gets or sets the fully qualified entity type name.
        /// </summary>
        public string FullTypeName { get; set; } = "";
        /// <summary>
        /// Gets or sets the collection name for the entity.
        /// </summary>
        public string CollectionName { get; set; } = "";
        /// <summary>
        /// Gets or sets the collection property name.
        /// </summary>
        public string? CollectionPropertyName { get; set; }
        /// <summary>
        /// Gets or sets the fully qualified collection identifier type name.
        /// </summary>
        public string? CollectionIdTypeFullName { get; set; }

        /// <summary>
        /// Gets the key property for the entity if one exists.
        /// </summary>
        public PropertyInfo? IdProperty => Properties.FirstOrDefault(p => p.IsKey);
        /// <summary>
        /// Gets or sets a value indicating whether IDs are automatically generated.
        /// </summary>
        public bool AutoId { get; set; }
        /// <summary>
        /// Gets or sets a value indicating whether the entity uses private setters.
        /// </summary>
        public bool HasPrivateSetters { get; set; }
        /// <summary>
        /// Gets or sets a value indicating whether the entity has a private or missing constructor.
        /// </summary>
        public bool HasPrivateOrNoConstructor { get; set; }

        /// <summary>
        /// Gets the entity properties.
        /// </summary>
        public List<PropertyInfo> Properties { get; } = new List<PropertyInfo>();
        /// <summary>
        /// Gets nested type metadata keyed by type name.
        /// </summary>
        public Dictionary<string, NestedTypeInfo> NestedTypes { get; } = new Dictionary<string, NestedTypeInfo>();
        /// <summary>
        /// Gets property names that should be ignored by mapping.
        /// </summary>
        public HashSet<string> IgnoredProperties { get; } = new HashSet<string>();
    }

    /// <summary>
    /// Contains metadata describing a mapped property.
    /// </summary>
    public class PropertyInfo
    {
        /// <summary>
        /// Gets or sets the property name.
        /// </summary>
        public string Name { get; set; } = "";
        /// <summary>
        /// Gets or sets the property type name.
        /// </summary>
        public string TypeName { get; set; } = "";
        /// <summary>
        /// Gets or sets the BSON field name.
        /// </summary>
        public string BsonFieldName { get; set; } = "";
        /// <summary>
        /// Gets or sets the database column type name.
        /// </summary>
        public string? ColumnTypeName { get; set; }
        /// <summary>
        /// Gets or sets a value indicating whether the property is nullable.
        /// </summary>
        public bool IsNullable { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether the property has a public setter.
        /// </summary>
        public bool HasPublicSetter { get; set; }
        /// <summary>
        /// Gets or sets a value indicating whether the property uses an init-only setter.
        /// </summary>
        public bool HasInitOnlySetter { get; set; }
        /// <summary>
        /// Gets or sets a value indicating whether the property has any setter.
        /// </summary>
        public bool HasAnySetter { get; set; }
        /// <summary>
        /// Gets or sets a value indicating whether the getter is read-only.
        /// </summary>
        public bool IsReadOnlyGetter { get; set; }
        /// <summary>
        /// Gets or sets the backing field name if available.
        /// </summary>
        public string? BackingFieldName { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether the property is the key.
        /// </summary>
        public bool IsKey { get; set; }
        /// <summary>
        /// Gets or sets a value indicating whether the property is required.
        /// </summary>
        public bool IsRequired { get; set; }
        /// <summary>
        /// Gets or sets the maximum allowed length.
        /// </summary>
        public int? MaxLength { get; set; }
        /// <summary>
        /// Gets or sets the minimum allowed length.
        /// </summary>
        public int? MinLength { get; set; }
        /// <summary>
        /// Gets or sets the minimum allowed range value.
        /// </summary>
        public double? RangeMin { get; set; }
        /// <summary>
        /// Gets or sets the maximum allowed range value.
        /// </summary>
        public double? RangeMax { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether the property is a collection.
        /// </summary>
        public bool IsCollection { get; set; }
        /// <summary>
        /// Gets or sets a value indicating whether the property is an array.
        /// </summary>
        public bool IsArray { get; set; }
        /// <summary>
        /// Gets or sets the collection item type name.
        /// </summary>
        public string? CollectionItemType { get; set; }
        /// <summary>
        /// Gets or sets the concrete collection type name.
        /// </summary>
        public string? CollectionConcreteTypeName { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether the property is a nested object.
        /// </summary>
        public bool IsNestedObject { get; set; }
        /// <summary>
        /// Gets or sets a value indicating whether collection items are nested objects.
        /// </summary>
        public bool IsCollectionItemNested { get; set; }
        /// <summary>
        /// Gets or sets the nested type name.
        /// </summary>
        public string? NestedTypeName { get; set; }
        /// <summary>
        /// Gets or sets the fully qualified nested type name.
        /// </summary>
        public string? NestedTypeFullName { get; set; }
        /// <summary>
        /// Gets or sets the converter type name.
        /// </summary>
        public string? ConverterTypeName { get; set; }
        /// <summary>
        /// Gets or sets the provider type name used by the converter.
        /// </summary>
        public string? ProviderTypeName { get; set; }
    }

    /// <summary>
    /// Contains metadata describing a nested type.
    /// </summary>
    public class NestedTypeInfo
    {
        /// <summary>
        /// Gets or sets the nested type name.
        /// </summary>
        public string Name { get; set; } = "";
        /// <summary>
        /// Gets or sets the nested type namespace.
        /// </summary>
        public string Namespace { get; set; } = "";
        /// <summary>
        /// Gets or sets the fully qualified nested type name.
        /// </summary>
        public string FullTypeName { get; set; } = "";
        /// <summary>
        /// Gets or sets the depth of the nested type.
        /// </summary>
        public int Depth { get; set; }

        /// <summary>
        /// Gets the nested type properties.
        /// </summary>
        public List<PropertyInfo> Properties { get; } = new List<PropertyInfo>();
        /// <summary>
        /// Gets nested type metadata keyed by type name.
        /// </summary>
        public Dictionary<string, NestedTypeInfo> NestedTypes { get; } = new Dictionary<string, NestedTypeInfo>();
    }
}
