using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

public class SingleThreadTaskScheduler : TaskScheduler, IDisposable
{
    private readonly BlockingCollection<Task> _tasks = new BlockingCollection<Task>();
    private readonly Thread _thread;
    public SynchronizationContext SyncContext { get; private set; }

    public SingleThreadTaskScheduler(string threadName)
    {
        var tcs = new TaskCompletionSource<bool>();
        _thread = new Thread(() =>
        {
            // Creiamo il contesto di sincronizzazione personalizzato
            SyncContext = new SingleThreadSynchronizationContext(this);
            SynchronizationContext.SetSynchronizationContext(SyncContext);
            tcs.SetResult(true);

            foreach (var task in _tasks.GetConsumingEnumerable())
            {
                base.TryExecuteTask(task);
            }
        })
        { IsBackground = true, Name = threadName };
        _thread.Start();
        tcs.Task.Wait(); // Aspetta che il thread sia pronto col suo contesto
    }

    private class SingleThreadSynchronizationContext : SynchronizationContext
    {
        private readonly SingleThreadTaskScheduler _sch;
        public SingleThreadSynchronizationContext(SingleThreadTaskScheduler sch) => _sch = sch;
        public override void Post(SendOrPostCallback d, object state)
            => Task.Factory.StartNew(() => d(state), CancellationToken.None, TaskCreationOptions.None, _sch);
    }

    protected override void QueueTask(Task task) => _tasks.Add(task);
    protected override bool TryExecuteTaskInline(Task task, bool prev)
        => Thread.CurrentThread == _thread && base.TryExecuteTask(task);
    protected override IEnumerable<Task> GetScheduledTasks() => _tasks;
    public override int MaximumConcurrencyLevel => 1;
    public void Dispose() => _tasks.CompleteAdding();
}