using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace Quik.VertexGenerator
{
    public class DrawQueue : IEnumerable<DrawCall>
    {
        private readonly RefList<QuikVertex> _vertices = new RefList<QuikVertex>();
        private readonly RefList<int> _elements = new RefList<int>();
        private readonly List<DrawCall> _drawCalls = new List<DrawCall>();
        private int _start;
        private int _baseOffset;
        private QRectangle _bounds;
        private QuikTexture _texture;

        public int ZDepth { get; private set; }
        public QuikVertex[] VertexArray => _vertices.InternalArray;
        public int VertexCount => _vertices.Count;
        public int[] ElementArray => _elements.InternalArray;
        public int ElementCount => _elements.Count;
        public int DrawCallCount => _drawCalls.Count;
        public int BaseOffset => _baseOffset;

        public void Clear()
        {
            _vertices.Clear();
            _elements.Clear();
            _drawCalls.Clear();
            ZDepth = 0;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void StartDrawCall(in QRectangle bounds, QuikTexture texture, int baseOffset)
        {
            _start = ElementCount;
            _texture = texture;
            _bounds = bounds;
            _baseOffset = baseOffset;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void StartDrawCall(in QRectangle bounds) => StartDrawCall(bounds, null, _vertices.Count);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void StartDrawCall(in QRectangle bounds, int baseOffset) => StartDrawCall(bounds, null, baseOffset);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void StartDrawCall(in QRectangle bounds, QuikTexture texture) => StartDrawCall(bounds, texture, _vertices.Count);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void AddVertex(in QuikVertex vertex)
        {
            _vertices.Add(in vertex);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void AddElement(int offset)
        {
            _elements.Add(offset + _baseOffset);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public int RestoreOffset(int baseOffset)
        {
            int old = _baseOffset;
            _baseOffset = baseOffset;
            return old;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public int RestoreOffset() => RestoreOffset(_vertices.Count);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public int AbsoluteElement(int offset)
        {
            return _baseOffset + offset;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public int RelativeElement(int baseOffset, int offset)
        {
            return AbsoluteElement(offset) - baseOffset;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void EndDrawCall()
        {
            int count = ElementCount - _start;
            _drawCalls.Add(new DrawCall(_start, count, _bounds, _texture));
        }

        public IEnumerator<DrawCall> GetEnumerator() => _drawCalls.GetEnumerator();
        IEnumerator IEnumerable.GetEnumerator() => _drawCalls.GetEnumerator();
    }

    public struct DrawCall
    {
        public int Start { get; }
        public int Count { get; }
        public QRectangle Bounds { get; }
        public QuikTexture Texture { get; }

        public DrawCall(int start, int count, in QRectangle bounds, QuikTexture texture)
        {
            Start = start;
            Count = count;
            Bounds = bounds;
            Texture = texture;
        }
    }
}