/**
 * 进程内读写锁模块
 * 参考 OpenCode 的实现，支持 using 语法
 */

export namespace Lock {
  const locks = new Map<
    string,
    {
      readers: number;
      writer: boolean;
      waitingReaders: (() => void)[];
      waitingWriters: (() => void)[];
    }
  >();

  function get(key: string) {
    if (!locks.has(key)) {
      locks.set(key, {
        readers: 0,
        writer: false,
        waitingReaders: [],
        waitingWriters: [],
      });
    }
    return locks.get(key)!;
  }

  function process(key: string) {
    const lock = locks.get(key);
    if (!lock || lock.writer || lock.readers > 0) return;

    // 优先处理写锁，防止写饥饿
    if (lock.waitingWriters.length > 0) {
      const nextWriter = lock.waitingWriters.shift()!;
      nextWriter();
      return;
    }

    // 唤醒所有等待的读锁
    while (lock.waitingReaders.length > 0) {
      const nextReader = lock.waitingReaders.shift()!;
      nextReader();
    }

    // 清理空闲锁
    if (
      lock.readers === 0 &&
      !lock.writer &&
      lock.waitingReaders.length === 0 &&
      lock.waitingWriters.length === 0
    ) {
      locks.delete(key);
    }
  }

  /**
   * 获取读锁
   * 多个读锁可以同时持有，但会被写锁阻塞
   */
  export async function read(key: string): Promise<Disposable> {
    const lock = get(key);

    return new Promise((resolve) => {
      if (!lock.writer && lock.waitingWriters.length === 0) {
        lock.readers++;
        resolve({
          [Symbol.dispose]: () => {
            lock.readers--;
            process(key);
          },
        });
      } else {
        lock.waitingReaders.push(() => {
          lock.readers++;
          resolve({
            [Symbol.dispose]: () => {
              lock.readers--;
              process(key);
            },
          });
        });
      }
    });
  }

  /**
   * 获取写锁
   * 写锁是排他的，必须等待所有读锁和写锁释放
   */
  export async function write(key: string): Promise<Disposable> {
    const lock = get(key);

    return new Promise((resolve) => {
      if (!lock.writer && lock.readers === 0) {
        lock.writer = true;
        resolve({
          [Symbol.dispose]: () => {
            lock.writer = false;
            process(key);
          },
        });
      } else {
        lock.waitingWriters.push(() => {
          lock.writer = true;
          resolve({
            [Symbol.dispose]: () => {
              lock.writer = false;
              process(key);
            },
          });
        });
      }
    });
  }

  /**
   * 带读锁执行操作
   */
  export async function withRead<T>(key: string, fn: () => Promise<T>): Promise<T> {
    using _ = await read(key);
    return fn();
  }

  /**
   * 带写锁执行操作
   */
  export async function withWrite<T>(key: string, fn: () => Promise<T>): Promise<T> {
    using _ = await write(key);
    return fn();
  }
}
