using System;
using System.Runtime.CompilerServices;

namespace AyCode.Core.Serializers.Binaries;

/// <summary>
/// Abstract base class for binary output implementations.
/// Provides only the buffer management strategy (grow/flush) — all write methods live in
/// BinarySerializationContext which owns the _buffer/_position state for zero virtual dispatch.
///
/// Derived classes implement:
/// - Initialize: provide the initial buffer and position
/// - Grow: handle buffer exhaustion (ArrayPool.Rent+copy or IBufferWriter.Advance+GetMemory)
/// - GetTotalPosition: compute total bytes written (for Position property, cold path)
/// </summary>
public interface IBinaryOutputBase
{
    /// <summary>
    /// Provides the initial buffer, starting position, and buffer end boundary.
    /// Called once before serialization begins.
    /// For ArrayBinaryOutput: Rent from ArrayPool, position = 0, bufferEnd = buffer.Length.
    /// For BufferWriterBinaryOutput: GetMemory + TryGetArray, position = segment.Offset, bufferEnd = segment.Offset + segment.Count.
    /// </summary>
    public void Initialize(out byte[] buffer, out int position, out int bufferEnd);

    /// <summary>
    /// Called when the context's buffer cannot hold 'needed' more bytes. Cold path only.
    /// Must provide a new or grown buffer via the ref parameters.
    /// For ArrayBinaryOutput: ArrayPool.Rent bigger buffer, copy old data, return old, position unchanged.
    /// For BufferWriterBinaryOutput: Advance current chunk, GetMemory new chunk, update buffer/position/bufferEnd.
    /// </summary>
    [MethodImpl(MethodImplOptions.NoInlining)]
    public void Grow(ref byte[] buffer, ref int position, ref int bufferEnd, int needed);

    /// <summary>
    /// Returns total bytes written so far, given the current position within the active buffer.
    /// Cold path — called only when Position property is accessed (typically once per serialization).
    /// For ArrayBinaryOutput: returns currentPosition directly (single contiguous buffer).
    /// For BufferWriterBinaryOutput: returns committedBytes + (currentPosition - chunkStart).
    /// </summary>
    public int GetTotalPosition(int currentPosition);

    /// <summary>
    /// Resets the output for reuse when the context is returned to the pool.
    /// Small buffers: keep as-is (faster than pool round-trip).
    /// Large buffers: return to pool, rent a smaller one (halved capacity).
    /// For BufferWriterBinaryOutput: no-op (chunks are owned by IBufferWriter).
    /// </summary>
    public void Reset();
}
