import { AsyncLocalStorage } from 'async_hooks';
import { Injectable } from '@nestjs/common';
import { TenantContext } from './tenant.types.js';

/**
 * 租户上下文存储接口
 */
interface TenantStore {
  tenant: TenantContext;
  userId?: string;
}

/**
 * 租户上下文服务
 * 使用 AsyncLocalStorage 实现请求级别的租户隔离
 */
@Injectable()
export class TenantContextService {
  private static storage = new AsyncLocalStorage<TenantStore>();

  /**
   * 在指定租户上下文中运行函数
   */
  run<T>(tenant: TenantContext, fn: () => T, userId?: string): T {
    return TenantContextService.storage.run({ tenant, userId }, fn);
  }

  /**
   * 在指定租户上下文中运行异步函数
   */
  runAsync<T>(tenant: TenantContext, fn: () => Promise<T>, userId?: string): Promise<T> {
    return TenantContextService.storage.run({ tenant, userId }, fn);
  }

  /**
   * 获取当前租户 ID
   */
  getCurrentTenantId(): string | undefined {
    return TenantContextService.storage.getStore()?.tenant.id;
  }

  /**
   * 获取当前租户 ID (必须存在，否则抛出异常)
   */
  requireTenantId(): string {
    const tenantId = this.getCurrentTenantId();
    if (!tenantId) {
      throw new Error('Tenant context not set. Ensure TenantContextMiddleware is applied.');
    }
    return tenantId;
  }

  /**
   * 获取当前租户上下文
   */
  getCurrentTenant(): TenantContext | undefined {
    return TenantContextService.storage.getStore()?.tenant;
  }

  /**
   * 获取当前租户上下文 (必须存在，否则抛出异常)
   */
  requireTenant(): TenantContext {
    const tenant = this.getCurrentTenant();
    if (!tenant) {
      throw new Error('Tenant context not set. Ensure TenantContextMiddleware is applied.');
    }
    return tenant;
  }

  /**
   * 获取当前用户 ID
   */
  getCurrentUserId(): string | undefined {
    return TenantContextService.storage.getStore()?.userId;
  }

  /**
   * 设置当前用户 ID (在已有租户上下文中)
   */
  setCurrentUserId(userId: string): void {
    const store = TenantContextService.storage.getStore();
    if (store) {
      store.userId = userId;
    }
  }

  /**
   * 检查租户上下文是否已设置
   */
  hasTenantContext(): boolean {
    return !!TenantContextService.storage.getStore()?.tenant;
  }

  /**
   * 检查当前租户状态是否为活跃
   */
  isTenantActive(): boolean {
    const tenant = this.getCurrentTenant();
    return tenant?.status === 'ACTIVE';
  }

  /**
   * 获取租户配置中的特定值
   */
  getTenantConfig<K extends keyof TenantContext['config']>(
    key: K,
  ): TenantContext['config'][K] | undefined {
    return this.getCurrentTenant()?.config[key];
  }
}
