using Inspectron.Fastbuffer.Interfaces;
using System.Collections.Concurrent;
using OpenCvSharp;
using Serilog;

namespace Inspectron.Fastbuffer.Filesystems;

public class AsyncFilesystem : IFilesystem
{
    private readonly DirectFilesystem _directFilesystem = new();
    private readonly List<string> _buffer = new();
    private readonly BlockingCollection<(string path, Mat data)> _writeQueue = new();
    private readonly Thread _backgroundThread;
    private readonly object _lock = new();

    public AsyncFilesystem()
    {
        _backgroundThread = new Thread(ProcessWriteQueue) { IsBackground = true };
        _backgroundThread.Name= "AsyncFilesystem";
        _backgroundThread.Start();
    }

    public void Write(string path, Mat data)
    {
        
        lock (_lock)
        {
            _buffer.Add(path);
            _writeQueue.Add((path, data));
            
        }
    }


    public void Delete(string path)
    {
        
        lock (_lock)
        {
            // pats is in buffer, so it's not written to disk yet
            if (_buffer.Contains(path))
            {
                _buffer.Remove(path);
                return;
            }
            _directFilesystem.Delete(path);
        }
        
    }

    private void ProcessWriteQueue()
    {
        foreach (var (path, data) in _writeQueue.GetConsumingEnumerable())
        {
            _directFilesystem.Write(path, data);
            lock (_lock)
                _buffer.Remove(path);
            if (_writeQueue.Count > 5)
                Log.Warning($"AsyncFilesystem write queue size: {_writeQueue.Count}");
        }
    }

    public void Dispose()
    {
        _writeQueue.CompleteAdding();
        _backgroundThread.Join();
    }

    public void Clear()
    {
        lock (_lock)
        {
            while (_writeQueue.TryTake(out _)) { }
        }
    }
}