using System.Runtime.CompilerServices;

namespace AyCode.Core.Serializers.Binaries;

/// <summary>
/// Abstract base interface for binary input implementations.
/// Provides only the buffer management strategy (initialize/advance) — all read methods live in
/// BinaryDeserializationContext which owns the _buffer/_position state for zero virtual dispatch.
///
/// Mirrors IBinaryOutputBase pattern from the serializer side.
///
/// Derived structs implement:
/// - Initialize: provide the initial buffer, position, and length
/// - TryAdvanceSegment: handle buffer exhaustion (return false for single-buffer, advance for multi-segment)
/// </summary>
public interface IBinaryInputBase
{
    /// <summary>
    /// Compile-time JIT-constant flag — true when the input is guaranteed to be a single contiguous buffer
    /// loaded entirely upfront (no cross-segment advance needed, no streaming-handoff needed). Used by
    /// <c>BinaryDeserializationContext.EnsureAvailable</c> to skip the bounds-check-and-segment-advance
    /// path on trusted inputs: <c>if (TInput.IsTrustedSingleSegment) return;</c> folds to a no-op via JIT
    /// generic-struct specialization, eliminating the per-read overhead.
    /// <para>Set <c>true</c> when: <see cref="ArrayBinaryInput"/> (single byte[] buffer, fully loaded).</para>
    /// <para>Set <c>false</c> when: <see cref="SequenceBinaryInput"/> (multi-segment ROS — cross-segment advance required),
    /// AsyncPipeReaderInputAdapter (streaming — chunk-arrival handoff required), or any other input that may
    /// dynamically advance buffers during deserialization.</para>
    /// <para><b>Trade-off in trusted mode</b>: corrupt-wire detection downgrades from a domain-specific
    /// <c>AcBinaryDeserializationException</c> to a generic <c>IndexOutOfRangeException</c>. Acceptable
    /// for byte[]-API consumers — the buffer is already validated by the caller.</para>
    /// </summary>
    static abstract bool IsTrustedSingleSegment { get; }

    /// <summary>
    /// Provides the initial buffer, starting position, and buffer length.
    /// Called once before deserialization begins.
    /// For ArrayBinaryInput: sets buffer = byte[], position = 0, bufferLength = data.Length.
    /// For SequenceBinaryInput: sets buffer to first segment's array, position/length to segment bounds.
    /// </summary>
    void Initialize(out byte[] buffer, out int position, out int bufferLength);

    /// <summary>
    /// Called when the context's buffer cannot satisfy 'needed' more bytes. Cold path only.
    /// Returns true if more data is available (segment advanced), false if end of input.
    /// For ArrayBinaryInput: always returns false (single contiguous buffer).
    /// For SequenceBinaryInput: advances to next segment, handles cross-boundary reads.
    /// </summary>
    [MethodImpl(MethodImplOptions.NoInlining)]
    bool TryAdvanceSegment(ref byte[] buffer, ref int position, ref int bufferLength, int needed);

    /// <summary>
    /// Releases any rented buffers (e.g. ArrayPool scratch in SequenceBinaryInput).
    /// Must be called after deserialization completes.
    /// For ArrayBinaryInput: no-op.
    /// </summary>
    void Release();
}
