using System;
using System.Threading;
using System.Threading.Tasks;

namespace PCL.Core.Utils.Threading;

// Partly generated by o4-mini-high (20250709)

/// <summary>
/// 使用两个线程池的调度器，分为 CPU 线程池和 IO 线程池，分别负责 CPU 密集型任务和 IO 密集型任务
/// </summary>
public class DualThreadPool
{
    /// <summary>
    /// 两线程池分别计算的最大线程数
    /// </summary>
    public int MaxThread { get; }

    private readonly TaskFactory _ioFactory;
    private readonly TaskFactory _cpuFactory;
    private readonly CancellationTokenSource _cts = new();

    /// <summary>
    /// 初始化 <see cref="DualThreadPool"/> 实例
    /// </summary>
    /// <param name="maxThread">参考 <see cref="MaxThread"/>，最小为 1</param>
    /// <exception cref="ArgumentOutOfRangeException">最大线程数小于 1</exception>
    public DualThreadPool(int maxThread)
    {
        if (maxThread < 1) throw new ArgumentOutOfRangeException(nameof(maxThread));

        MaxThread = maxThread;

        var ioScheduler = new LimitedConcurrencyLevelTaskScheduler(maxThread);
        var cpuScheduler = new LimitedConcurrencyLevelTaskScheduler(maxThread);
        var cancellationToken = _cts.Token;

        // DenyChildAttach 防止子任务跑到外层 scheduler
        _ioFactory = new TaskFactory(
            cancellationToken,
            TaskCreationOptions.DenyChildAttach,
            TaskContinuationOptions.None,
            ioScheduler);

        _cpuFactory = new TaskFactory(
            cancellationToken,
            TaskCreationOptions.DenyChildAttach,
            TaskContinuationOptions.None,
            cpuScheduler);
    }

    /// <summary>
    /// 提交一段 IO 密集工作
    /// </summary>
    public Task QueueIo(Action work) => _ioFactory.StartNew(work);

    /// <summary>
    /// 提交一段异步 IO 密集工作
    /// </summary>
    public Task QueueIo(Func<Task> work) => _ioFactory.StartNew(work).Unwrap();

    /// <summary>
    /// 提交一段 CPU 密集工作
    /// </summary>
    public Task QueueCpu(Action work) => _cpuFactory.StartNew(work);

    /// <summary>
    /// 提交一段异步 CPU 密集工作
    /// </summary>
    public Task QueueCpu(Func<Task> work) => _cpuFactory.StartNew(work).Unwrap();

    /// <summary>
    /// 取消所有正在执行的工作
    /// </summary>
    public void CancelAll() => _cts.Cancel();
}
