/**
 * @file 测试容器辅助类
 * @description 基于 DI 子容器机制,提供测试环境下的服务 Mock 注入与隔离能力
 * @author JunBin.Yang
 */

import { getContainer, Container, setContainer, ServiceKey } from "@core/di";

/**
 * 测试容器辅助类
 * 通过创建子容器实现测试隔离,子容器中注册的 Mock 服务优先于父容器的真实服务
 * @example
 * const helper = new TestContainerHelper();
 * helper.setup();
 * helper.registerMock<IAuthRepository>(AUTH_REPOSITORY_KEY, mockAuthRepo);
 * // ... 执行测试 ...
 * helper.teardown();
 */
export class TestContainerHelper {
  private originalContainer: Container | undefined;
  private testContainer: Container | undefined;
  private isSetup: boolean = false;

  /**
   * 初始化测试环境
   * 保存当前全局容器引用,创建子容器并替换全局容器
   * @throws 重复调用 setup() 而未 teardown() 时抛出异常
   */
  setup(): void {
    if (this.isSetup) {
      throw new Error("[TestContainerHelper] 请先调用 teardown() 再重新 setup()");
    }
    this.originalContainer = getContainer();
    this.testContainer = this.originalContainer.createChild();
    setContainer(this.testContainer);
    this.isSetup = true;
  }

  /**
   * 注册 Mock 服务到测试子容器
   * @template T 服务类型
   * @param key 服务标识符
   * @param mock Mock 服务实例
   * @throws 未调用 setup() 时抛出异常
   */
  registerMock<T>(key: ServiceKey, mock: T): void {
    if (!this.isSetup || !this.testContainer) {
      throw new Error("[TestContainerHelper] 请先调用 setup() 再注册 Mock 服务");
    }
    this.testContainer.register<T>(key, () => mock);
  }

  /**
   * 清理测试环境,恢复原始全局容器
   */
  teardown(): void {
    if (this.originalContainer) {
      setContainer(this.originalContainer);
    }
    this.originalContainer = undefined;
    this.testContainer = undefined;
    this.isSetup = false;
  }
}