using CareFusion.Mosaic.Interfaces.Converters;
using CareFusion.Mosaic.Interfaces.Messages.Stock;
using CareFusion.Mosaic.Interfaces.Types.Packs;
using Rowa.Observables;
using StorageSystem.Simulator;
using StorageSystem.Simulator.Cores.StockUpdateHandler;
using StorageSystem.Simulator.Interfaces;
using System;
using System.Collections.Generic;

namespace StorageSystemSimulator.Cores
{
    public class SimulatorStockUpdateCore
    {
        private List<IConverterStream> _converterStreams = new();
        private StorageSystemStock _stock;

        private readonly SourceSubject<StockUpdateConfig> _config = new();
        private readonly Subject<RobotPack> _updatedRobotPacks = new();

        private IStockUpdateRequestHandler _currentHandler;

        // not strictly necessary to keep here because the disposable is kept alive until end of program
        // but more explicit
        private readonly IDisposable _internalConfigSourceSubscription;

        public SimulatorStockUpdateCore()
        {
            _internalConfigSourceSubscription = _config.Subscribe(new DelegateObserver<StockUpdateConfig>(
                n =>
                {
                    _currentHandler = n.Behaviour switch
                    {
                        StockUpdateBehaviour.AccordingToStock => new AccordingToStockHandler(_stock, p => _updatedRobotPacks.Current = p, _converterStreams),
                        StockUpdateBehaviour.AlwaysAccept => new AlwaysAcceptHandler(_converterStreams),
                        StockUpdateBehaviour.AlwaysReject => new AlwaysRejectHandler(n.Reason, _converterStreams),
                        _ => throw new ArgumentOutOfRangeException()
                    };
                }, onComplete: () => _internalConfigSourceSubscription?.Dispose()));
        }

        public void Initialize(List<IConverterStream> converterStreams, StorageSystemStock stock)
        {
            _converterStreams = converterStreams;
            _stock = stock;
        }

        public void SetConfigSource(IObservable<StockUpdateConfig> configSource)
        {
            
            _config.SetSource(configSource);
        }


        public void ProcessStockUpdateRequest(StockUpdateRequest request)
        {
            _currentHandler?.Handle(request);
        }

        public IObservable<RobotPack> UpdatedRobotPacks => _updatedRobotPacks;
    }
}
