using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Reactive.Threading.Tasks;
using CliWrap;

namespace InnovEnergy.Lib.Utils.WIP;

using Data = IReadOnlyList<Byte>;

public class ObservableProcess
{
    private readonly Command _Command;
    private readonly CancellationTokenSource _Kill      = new CancellationTokenSource();
    private readonly CancellationTokenSource _Interrupt = new CancellationTokenSource();
    
    private readonly ObserverPipeSource _StdIn  = new ObserverPipeSource();
    private readonly ReadablePipeTarget _StdOut = new ReadablePipeTarget();
    private readonly ReadablePipeTarget _StdErr = new ReadablePipeTarget();

    public IObserver<Data>   StdIn  => _StdIn;

    private readonly Subject<Int32> _Pid      = new Subject<Int32>();
    private readonly Subject<Int32> _ExitCode = new Subject<Int32>();

    public Task<Int32> Pid      { get; }  
    public Task<Int32> ExitCode { get; }


    public Task<Data> Read(Int32 nBytes) => _StdOut.Read(nBytes);

    public ObservableProcess(Command command)
    {
        _Command = command;
        Pid      = _Pid.ToTask();
        ExitCode = _ExitCode.ToTask();
    }

    public void Start()
    {
        var commandTask = _Command
                          .WithStandardInputPipe(_StdIn)
                          .WithStandardOutputPipe(_StdOut)
                          .WithStandardErrorPipe(_StdErr)
                          .ExecuteAsync(_Kill.Token, _Interrupt.Token);
        
        _Pid.OnNext(commandTask.ProcessId);

        commandTask.Task
                   .ToObservable()
                   .Select(t => t.ExitCode)
                   .Subscribe(_ExitCode); 
    }

    public void Kill()      => _Kill.Cancel();
    public void Interrupt() => _Interrupt.Cancel();
}