using System.Diagnostics;

namespace skyscraper8.UI.MonoGame.Bridge;

public class ZigguratStream : Stream
{
    public ZigguratStream()
    {
        _ziggurat = new Ziggurat();
    }
    
    public ZigguratStream(int seed)
    {
        _ziggurat = new Ziggurat(seed);
    }

    public ZigguratStream(Random random)
    {
        _ziggurat = new Ziggurat(random);
    }

    private Ziggurat _ziggurat;
    private double minZig, maxZig;
    private byte getNextByte()
    {
        double sample = _ziggurat.Sample();
        double oldMin = minZig;
        double oldMax = maxZig;
        minZig = System.Math.Min(minZig, sample);
        maxZig = System.Math.Max(maxZig, sample);
        if (oldMin != minZig || oldMax != maxZig)
        {
            return getNextByte();
        }

        sample += (minZig / -1.0);
        double span = (minZig / -1.0) + maxZig;
        double sampleScaled = sample / span;
        Debug.Assert(sampleScaled <= 1.0);
        sampleScaled *= 255.0;
        byte scaledByte = (byte)sampleScaled;
        
        return scaledByte;
    }
    
    public override void Flush()
    {
        throw new NotSupportedException();
    }

    private long internalPosition;
    public override int Read(byte[] buffer, int offset, int count)
    {
        for (int i = 0; i < count; i++)
        {
            buffer[offset + i] = getNextByte();
            internalPosition++;
        }
        return count;
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        throw new NotSupportedException();
    }

    public override void SetLength(long value)
    {
        throw new NotSupportedException();
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        throw new NotSupportedException();
    }

    public override bool CanRead => true;
    public override bool CanSeek => false;
    public override bool CanWrite => false;
    public override long Length => throw new NotSupportedException();
    public override long Position { get => internalPosition; set => throw new NotSupportedException(); }
}