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

// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable UnusedType.Global

#pragma warning disable CS8766 // Nullability of reference types in return type doesn't match implicitly implemented member (possibly because of nullability attributes).

namespace NodePipeline.Abstractions.Models;

/// <summary>
///     Node field class
///     <para>Wraps value and can be a port with <c>Input</c> or <c>Output</c> direction or a <c>Parameter</c>.</para>
/// </summary>
/// <typeparam name="T"></typeparam>
public class NodeField<T> : INodeField<T>
{
    private Func<T>? _getter;
    private Action<T>? _setter;
    private T _value = default!;

    /// <summary>
    ///     Node field name
    /// </summary>
    public string Name { get; set; } = string.Empty;

    /// <summary>
    ///     Node field description
    /// </summary>
    public string? Description { get; set; }

    /// <summary>
    ///     Node field code (with node id)
    /// </summary>
    public string Code { get; set; } = string.Empty;

    /// <summary>
    ///     Node field direction
    ///     <para>
    ///         Port directions: <c>Input</c>, <c>Output</c>
    ///         <br />
    ///         Parameter: <c>Parameter</c>
    ///     </para>
    /// </summary>
    public FieldDirection Direction { get; set; }

    /// <summary>
    ///     Node field value
    /// </summary>
    public T Value
    {
        get => _getter != null ? _getter() : _value;
        set
        {
            if (_setter != null) _setter(value);
            else _value = value;
        }
    }

    /// <summary>
    ///     Static binding (during pipeline building)
    /// </summary>
    /// <param name="outputPort"></param>
    public void BindStatic(INodeField<T> outputPort)
    {
        _getter = () => outputPort.Value;
        _setter = v => outputPort.Value = v;
    }

    /// <summary>
    ///     Runtime binding (during pipeline Execution)
    /// </summary>
    /// <param name="getter"></param>
    /// <param name="setter"></param>
    public void BindRuntime(Func<T> getter, Action<T>? setter)
    {
        _getter = getter;
        _setter = setter ?? (_ => { });
    }
}

#pragma warning restore CS8766 // Nullability of reference types in return type doesn't match implicitly implemented member (possibly because of nullability attributes).