using OpenCvSharp;
using System.Drawing;
using System.Threading.Channels;
using Ninject;
using VisionBuilder.UI.Common;
using VisionBuilder.UI.Common.Processing;

namespace Hawkeye.VisionBuilder.UI.Sources.Emulation
{
    public class EmulationCameraImageSource:IImageSource, IVisionBuilderModule
    {
        private readonly EmulationSettings _settings;
        private readonly string _name;
        private string _currentFolder;
        private string[] _selectedFiles;

        public EmulationCameraImageSource(EmulationSettings settings)
        {
            _settings = settings;
        }

        public string GetName()
        {
            return _name;
        }

        private Channel<Mat> _channel = Channel.CreateBounded<Mat>(new BoundedChannelOptions(1)
        {
            FullMode = BoundedChannelFullMode.DropOldest,
            SingleReader = true,
            SingleWriter = true,
            AllowSynchronousContinuations = true
        });
        public async Task<Mat> GetImage(CancellationToken token)
        {
            //clear the channel if it is full
            if (_channel.Reader.Count > 0)
            {
                while (_channel.Reader.TryRead(out _)) { }
            }
            //get the next image
            await Task.Run(new Action(() => _ = GetImageInternal(CancellationToken.None)), token);

            return await _channel.Reader.ReadAsync(token);
        }

        public async Task<Mat> GetImageInternal(CancellationToken token)
        {
            if (_selectedFiles.Length == 0) return null;
            var id = (_index) % _selectedFiles.Length;
            if (id == 0)
            {
                if (_index > 0)
                    OnLoopOver();
                if (_settings.SingleRun && _index > 0)
                {
                    // infinite sleep
                    await Task.Delay(Timeout.Infinite, token);
                }
                Console.WriteLine("starting new emulation cycle");
                await Task.Delay(_settings.CycleDelay, token);
            }
            else
            {
                await Task.Delay(_settings.PerImageDelay, token);
            }

            var path = _selectedFiles[id];
            _index++;
            
            

            Console.WriteLine($"Getting image {path}");
            var res= Cv2.ImRead(path);
            await _channel.Writer.WriteAsync(res, token);
            return res;
        }
        public void SetFolder(string imagesFolder)
        {
            try
            {
                _currentFolder = imagesFolder;
                var path = Path.Combine("..", "Data", "Emulation", imagesFolder);
                _selectedFiles = Directory.GetFiles(path, "*.bmp")
                    .Concat(Directory.GetFiles(path, "*.png"))
                    .Concat(Directory.GetFiles(path, "*.jpg"))
                    .Where(x => !Path.GetFileNameWithoutExtension(x).Contains("_analysis"))
                    .ToArray();
            }
            catch
            {
            }
        }

        public void SetFolderAbsolute(string imagesFolder)
        {
            try
            {
                _currentFolder = imagesFolder;
                var path = imagesFolder;
                _selectedFiles = Directory.GetFiles(path, "*.bmp")
                    .Concat(Directory.GetFiles(path, "*.png"))
                    .Concat(Directory.GetFiles(path, "*.jpg"))
                    .Where(x => !Path.GetFileNameWithoutExtension(x).Contains("_analysis"))
                    .ToArray();
            }
            catch
            {
            }
        }

        
        public event Action OnLoopOver = delegate { };
        private int _index = 0;


        public void InitializeModule()
        {
            if(string.IsNullOrEmpty(_settings.EmulationPath)) return;
            SetFolderAbsolute(_settings.EmulationPath);
        }
    }
}
