/**
 * 全局 LLM 并发控制器
 *
 * 解决 issue：多个书籍同时生成时，各自的 AsyncPool 互不感知，
 * 导致总计并发数可能超过供应商 Rate Limit。
 *
 * 使用信号量模式，全局统一控制所有书籍生成任务的最大并发数。
 *
 * 并发数可通过环境变量 LLM_GLOBAL_CONCURRENCY 配置，默认 10。
 */

/** 默认全局最大并发数 */
const DEFAULT_GLOBAL_CONCURRENCY = 10;

/** 默认单书最大并发数 */
const DEFAULT_BOOK_CONCURRENCY = 8;

/**
 * 简易信号量实现（无外部依赖）
 */
class SimpleSemaphore {
  private current = 0;
  private waitQueue: Array<() => void> = [];

  constructor(private max: number) {}

  async acquire(): Promise<() => void> {
    if (this.current < this.max) {
      this.current++;
      return () => { this.current--; this.processQueue(); };
    }
    // 等待队列
    return new Promise<() => void>((resolve) => {
      this.waitQueue.push(() => {
        this.current++;
        resolve(() => { this.current--; this.processQueue(); });
      });
    });
  }

  private processQueue() {
    if (this.waitQueue.length > 0 && this.current < this.max) {
      const next = this.waitQueue.shift()!;
      next();
    }
  }
}

/** 全局信号量实例（单例） */
let globalSemaphore: SimpleSemaphore | null = null;

/**
 * 获取全局并发限制
 */
function getGlobalMaxConcurrency(): number {
  const env = process.env['LLM_GLOBAL_CONCURRENCY'];
  if (env) {
    const parsed = parseInt(env, 10);
    if (!isNaN(parsed) && parsed > 0) return parsed;
  }
  return DEFAULT_GLOBAL_CONCURRENCY;
}

/**
 * 获取单书最大并发数（可配置）
 */
export function getBookConcurrency(): number {
  const env = process.env['LLM_BOOK_CONCURRENCY'];
  if (env) {
    const parsed = parseInt(env, 10);
    if (!isNaN(parsed) && parsed > 0) return parsed;
  }
  return DEFAULT_BOOK_CONCURRENCY;
}

/**
 * 获取全局信号量（懒初始化单例）
 */
function getGlobalSemaphore(): SimpleSemaphore {
  if (!globalSemaphore) {
    globalSemaphore = new SimpleSemaphore(getGlobalMaxConcurrency());
    console.log(`[LLM-Concurrency] 全局信号量初始化: max=${getGlobalMaxConcurrency()}`);
  }
  return globalSemaphore;
}

/**
 * 在全局并发控制下执行异步任务。
 *
 * 使用方式：
 *   const result = await withGlobalLLMConcurrency(() => callLLMWithMessages(...));
 *
 * 如果全局槽位满了，调用方会排队等待，而非直接报错。
 *
 * @param fn 需要执行的 LLM 调用函数
 * @returns fn 的返回值
 */
export async function withGlobalLLMConcurrency<T>(fn: () => Promise<T>): Promise<T> {
  const semaphore = getGlobalSemaphore();
  const release = await semaphore.acquire();
  try {
    return await fn();
  } finally {
    release();
  }
}

/**
 * 获取当前全局信号量状态（用于监控/调试）
 */
export function getConcurrencyStatus(): { max: number; running: number; waiting: number } {
  const semaphore = getGlobalSemaphore();
  // async-mutex 的 Semaphore 没有公共 API 暴露等待数，这里做一个合理近似
  return {
    max: getGlobalMaxConcurrency(),
    running: -1, // 无法精确获取，需要自行维护计数器
    waiting: -1,
  };
}
