import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { Prisma } from '@prisma/client';

export type TransactionClient = Omit<
  PrismaService,
  '$connect' | '$disconnect' | '$on' | '$transaction' | '$use' | '$extends'
>;

/**
 * 工作单元模式
 * 用于管理事务边界，确保多个仓库操作在同一事务中执行
 */
@Injectable()
export class UnitOfWork {
  private transactionClient: TransactionClient | null = null;

  constructor(private readonly prisma: PrismaService) {}

  /**
   * 获取当前事务客户端，如果没有活跃事务则返回普通客户端
   */
  getClient(): TransactionClient {
    return this.transactionClient || this.prisma;
  }

  /**
   * 在事务中执行操作
   */
  async executeInTransaction<T>(
    operation: (client: TransactionClient) => Promise<T>,
    options?: {
      maxWait?: number;
      timeout?: number;
      isolationLevel?: Prisma.TransactionIsolationLevel;
    },
  ): Promise<T> {
    return this.prisma.$transaction(
      async (tx) => {
        this.transactionClient = tx as TransactionClient;
        try {
          return await operation(tx as TransactionClient);
        } finally {
          this.transactionClient = null;
        }
      },
      {
        maxWait: options?.maxWait ?? 5000,
        timeout: options?.timeout ?? 10000,
        isolationLevel: options?.isolationLevel ?? Prisma.TransactionIsolationLevel.ReadCommitted,
      },
    );
  }

  /**
   * 是否在事务中
   */
  isInTransaction(): boolean {
    return this.transactionClient !== null;
  }
}
