using System;
using System.Collections.Generic;
using NodePipeline.Abstractions.Interfaces.Nodes;

// ReSharper disable ConvertToPrimaryConstructor

namespace NodePipeline.Engine.CodeGeneration.Abstractions.Models;

public sealed class NodeFieldDescriptor
{
    public NodeFieldDescriptor(string propertyName, string fieldName, string valueType, bool isNullableValueType,
        bool isValueReferenceType, bool isValueEnum, FieldDirection direction, NodeFieldMetaData? metaData)
    {
        PropertyName = propertyName ?? throw new ArgumentNullException(nameof(propertyName));
        FieldName = fieldName ?? throw new ArgumentNullException(nameof(fieldName));
        ValueType = valueType ?? throw new ArgumentNullException(nameof(valueType));
        IsNullableValueType = isNullableValueType;
        IsValueReferenceType = isValueReferenceType;
        IsValueEnum = isValueEnum;
        Direction = direction;

        Metadata = metaData;
    }

    /// <summary>
    ///     C# property name
    /// </summary>
    public string PropertyName { get; }

    /// <summary>
    ///     Node field name (used by mentioning in pipeline configuration)
    /// </summary>
    public string FieldName { get; }

    /// <summary>
    ///     Underlying value type
    /// </summary>
    public string ValueType { get; }

    public bool IsNullableValueType { get; }
    public bool IsValueReferenceType { get; }
    public bool IsValueEnum { get; }

    /// <summary>
    ///     Node field direction
    /// </summary>
    public FieldDirection Direction { get; }

    /// <summary>
    ///     node field metadata
    /// </summary>
    public NodeFieldMetaData? Metadata { get; }

    /// <summary>
    ///     Node field metadata
    /// </summary>
    public class NodeFieldMetaData
    {
        private readonly HashSet<ValidatorDescriptor> _customValidators = [];

        public NodeFieldMetaData(bool isRequired, bool disallowNullableOutput = false,
            IEnumerable<ValidatorDescriptor>? customValidators = null,
            object? defaultValue = null, bool canDefaultValueBeInitialized = false, decimal? numberMinBound = null,
            decimal? numberMaxBound = null, int? stringMinLength = null, int? stringMaxLength = null)
        {
            IsRequired = isRequired;
            DefaultValue = defaultValue;
            CanDefaultValueBeInitialized = canDefaultValueBeInitialized;
            NumberMinBound = numberMinBound;
            NumberMaxBound = numberMaxBound;
            StringMinLength = stringMinLength;
            StringMaxLength = stringMaxLength;
            DisallowNullableOutput = disallowNullableOutput;

            if (customValidators == null) return;
            foreach (var validatorType in customValidators) _customValidators.Add(validatorType);
        }

        public IReadOnlyCollection<ValidatorDescriptor> CustomValidators => _customValidators;
        public object? DefaultValue { get; }
        public bool CanDefaultValueBeInitialized { get; }
        public bool IsRequired { get; }

        /// <summary>
        ///     It is suitable for ports only
        /// </summary>
        public bool DisallowNullableOutput { get; }

        public decimal? NumberMinBound { get; }
        public decimal? NumberMaxBound { get; }

        public int? StringMinLength { get; }
        public int? StringMaxLength { get; }
    }
}