using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Hex_2048
{
    // written using GoogleAI 20260525 1759 
    public class LoopStream : WaveStream
    {
        private WaveStream _currentSource;
        private readonly object _lockObject = new object();

        public string PendingNextFilePath { get; set; } = null;
        public event EventHandler LoopReachedEnd;

        // ADD THIS FLAG (Defaults to true)
        public bool EnableLooping { get; set; } = true;

        public LoopStream(WaveStream initialSource)
        {
            _currentSource = initialSource;
        }

        public override WaveFormat WaveFormat => _currentSource.WaveFormat;
        public override long Length => _currentSource.Length;
        public override long Position
        {
            get => _currentSource.Position;
            set => _currentSource.Position = value;
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            lock (_lockObject)
            {
                int totalBytesRead = 0;

                while (totalBytesRead < count)
                {
                    int bytesRead = _currentSource.Read(buffer, offset + totalBytesRead, count - totalBytesRead);

                    if (bytesRead == 0)
                    {
                        // Track reached the end
                        LoopReachedEnd?.Invoke(this, EventArgs.Empty);

                        // 1. Check if a new track is queued up
                        if (!string.IsNullOrEmpty(PendingNextFilePath))
                        {
                            _currentSource.Dispose();
                            _currentSource = new AudioFileReader(PendingNextFilePath);
                            PendingNextFilePath = null;
                        }
                        // 2. If NO new track, check if we should loop the current one
                        else if (EnableLooping)
                        {
                            if (_currentSource.Position == 0) break;
                            _currentSource.Position = 0;
                        }
                        // 3. Looping is disabled and no track is next: stop playback entirely
                        else
                        {
                            break;
                        }
                    }

                    totalBytesRead += bytesRead;
                }

                return totalBytesRead;
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                lock (_lockObject)
                {
                    _currentSource?.Dispose();
                    _currentSource = null;
                }
            }
            base.Dispose(disposing);
        }
    }


    public class WaveOut_Mine : WaveOut, IDisposable
    {
        private string _strName = "";
        private LoopStream _loopStream = null;

        // Fires on the audio thread right before a track loops or transitions
        public event EventHandler TrackLooped;

        public string Name => _strName;

        // Constructor enforces FunctionCallback to fix the WinForms background thread issue
        public WaveOut_Mine(string strName) : base(WaveCallbackInfo.FunctionCallback())
        {
            this._strName = strName;
        }
        public bool EnableLooping
        {
            get => _loopStream != null && _loopStream.EnableLooping;
            set
            {
                if (_loopStream != null)
                {
                    _loopStream.EnableLooping = value;
                }
            }
        }
        public LoopStream loopStream
        {
            get => _loopStream;
            set
            {
                // Unhook event from the old stream if one existed
                if (_loopStream != null)
                {
                    _loopStream.LoopReachedEnd -= OnLoopStreamReachedEnd;
                }

                _loopStream = value;

                // Hook event into the new stream
                if (_loopStream != null)
                {
                    _loopStream.LoopReachedEnd += OnLoopStreamReachedEnd;
                }
            }
        }

        /// <summary>
        /// Property for the game engine. Assign a file path here to queue up 
        /// the next track at the end of the current loop cycle.
        /// </summary>
        public string wo_Next
        {
            get => _loopStream?.PendingNextFilePath;
            set
            {
                if (_loopStream != null)
                {
                    _loopStream.PendingNextFilePath = value;
                }
            }
        }

        private void OnLoopStreamReachedEnd(object sender, EventArgs e)
        {
            // Bubble the event up to your Form or Game Manager layer
            TrackLooped?.Invoke(this, EventArgs.Empty);
        }

        /// <summary>
        /// Custom explicit cleanup. Hides the base class Dispose method using 'new'
        /// to safely clean up both our LoopStream and the underlying audio hardware.
        /// </summary>
        public new void Dispose()
        {
            // 1. Clean up the loop stream layer
            if (_loopStream != null)
            {
                _loopStream.LoopReachedEnd -= OnLoopStreamReachedEnd;
                _loopStream.Dispose();
                _loopStream = null;
            }

            // 2. Clear out any external Form listeners to prevent memory leaks
            TrackLooped = null;

            // 3. Call NAudio's internal hardware disposal
            base.Dispose();
        }
    }


    //public class WaveOut_Mine : WaveOut
    //{
    //    string strName = "";
    //    public string Name
    //    {
    //        get { return strName; }
    //    }
    //    public WaveOut_Mine(string strName )
    //    {
    //        this.strName = strName;
    //    }

    //    LoopStream _loopStream = null;
    //    public LoopStream loopStream
    //    {
    //        get { return _loopStream; }
    //        set { _loopStream = value; }
    //    }
    //}

    ///// <summary>
    ///// Stream for looping playback
    ///// https://markheath.net/post/looped-playback-in-net-with-naudio
    ///// </summary>
    //public class LoopStream : WaveStream
    //{
    //    WaveStream sourceStream;

    //    /// <summary>
    //    /// Creates a new Loop stream
    //    /// </summary>
    //    /// <param name="sourceStream">The stream to read from. Note: the Read method of this stream should return 0 when it reaches the end
    //    /// or else we will not loop to the start again.</param>
    //    public LoopStream(WaveStream sourceStream)
    //    {
    //        this.sourceStream = sourceStream;
    //        this.EnableLooping = true;
    //    }


    //    /// <summary>
    //    /// Use this to turn looping on or off
    //    /// </summary>
    //    public bool EnableLooping { get; set; }

    //    /// <summary>
    //    /// Return source stream's wave format
    //    /// </summary>
    //    public override WaveFormat WaveFormat
    //    {
    //        get { return sourceStream.WaveFormat; }
    //    }

    //    /// <summary>
    //    /// LoopStream simply returns
    //    /// </summary>
    //    public override long Length
    //    {
    //        get { return sourceStream.Length; }
    //    }

    //    /// <summary>
    //    /// LoopStream simply passes on positioning to source stream
    //    /// </summary>
    //    public override long Position
    //    {
    //        get { return sourceStream.Position; }
    //        set 
    //        {
    //            sourceStream.Position = value; 

    //        }
    //    }

    //    public override int Read(byte[] buffer, int offset, int count)
    //    {
    //        int totalBytesRead = 0;

    //        while (totalBytesRead < count)
    //        {
    //            int bytesRead = sourceStream.Read(buffer, offset + totalBytesRead, count - totalBytesRead);
    //            if (bytesRead == 0)
    //            {
    //                if (sourceStream.Position == 0 || !EnableLooping)
    //                {
    //                    // something wrong with the source stream
    //                    break;
    //                }
    //                // loop
    //                sourceStream.Position = 0;
    //            }
    //            totalBytesRead += bytesRead;
    //        }
    //        return totalBytesRead;
    //    }
    //}

}
