using System.IO.Ports;
using System.Text;
using MaterialSkin.Controls;
using Serilog;
using VisionBuilder.UI.Common;
using VisionBuilder.UI.Common.Processing;
using VisionBuilder.UI.Statistics;

namespace CandyboxPlugin.Modules.Barcode;

public class CandyboxBarcodeReader : IVisionBuilderModule
{
    private readonly ILoadingService _loadingService;

    private readonly CandyboxBarcodeReaderSettings _settings;
    private readonly SingleCameraVM _singleCameraVm;
    private readonly VisionBuilderStatistics _statistics;
    private SerialPort _port;
    public EReaderState _readerState = EReaderState.ReadingRecipe;
    private MaterialCancellableLoader? _loader;

    public CandyboxBarcodeReader(CandyboxBarcodeReaderSettings settings, SingleCameraVM singleCameraVm, VisionBuilderStatistics statistics)
    {
        _settings = settings;
        _singleCameraVm = singleCameraVm;
        _statistics = statistics;
    }

    private void _port_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        Thread.Sleep(500);
        if(_singleCameraVm.IsRunning)return;
        if(_readerState == EReaderState.ReadingRecipe)
            ReadRecipe();
        if (_readerState == EReaderState.ReadingAUF)
            ReadAUF();
    }

    private void ReadRecipe()
    {
        if (_singleCameraVm.IsRunning) return;

        byte[] buffer = new byte[_port.BytesToRead];
        _port.Read(buffer, 0, _port.BytesToRead);
        var data = Encoding.ASCII.GetString(buffer).Trim();
        if (string.IsNullOrEmpty(data))
        {
            Log.Warning("Received empty recipe");
            return;
        }
        var vm = _singleCameraVm.GetRecipeSelectionVm();
        var recipes = vm.Recipes;

        string searchString = data;
        Log.Information("Read Recipe: {Recipe}", data);
        if (_settings.BarcodeRecipeMappings.Any(x => x.Barcode == searchString))
        {
            searchString = _settings.BarcodeRecipeMappings.First(x => x.Barcode == searchString).RecipeName;
        }

        var existingRecipe = recipes.FirstOrDefault(x => x.RecipeName == searchString);
        if (existingRecipe == null)
        {
            Log.Warning("No matching recipe found for data: {Data}", data);
            return;
        }
        vm.SelectedRecipe = vm.Recipes.FirstOrDefault(r => r.RecipeName == existingRecipe.RecipeName);
        _singleCameraVm.SynchronizationContext!.Post((_) =>
        {
            _loader = new MaterialCancellableLoader();
            _loader.StartLoading("Waiting for AUF...");
            _loader.LoadingCancelled += CancelWaiting;
            _singleCameraVm.ProcessRecipeSelectionVm(vm);
        }, null);
        Application.DoEvents();
        _readerState = EReaderState.ReadingAUF;
        
    }

    private void CancelWaiting(object? sender, string e)
    {
        _singleCameraVm.SynchronizationContext!.Post((_) =>
        {
            _loader.FinishLoading("Waiting for AUF...");
            _loader.LoadingCancelled -= CancelWaiting;
            _loader = null;
        }, null);
        _readerState = EReaderState.ReadingRecipe;
        
    }

    private void ReadAUF()
    {
        byte[] buffer = new byte[_port.BytesToRead];
        _port.Read(buffer, 0, _port.BytesToRead);
        var data = Encoding.ASCII.GetString(buffer).Trim();
        if (string.IsNullOrEmpty(data))
        {
            Log.Warning("Received empty AUF");
            return;
        }
        Log.Information("Read AUF: {AUF}", data);
        if (_loader != null)
        {
            CancelWaiting(this, string.Empty);
        }


        _statistics.Metadata = data;
        _=_singleCameraVm.Start().ConfigureAwait(false);
        Application.DoEvents();
        _readerState = EReaderState.ReadingRecipe;
    }


    public void InitializeModule()
    {
        try
        {
            _port = new SerialPort(_settings.ComPort, 9600);
            _port.Open();
            _port.DataReceived += _port_DataReceived;
        }
        catch (Exception e)
        {
            Log.Warning(e, "Failed to open com-port");
        }

    }
}