import { DynamicModule, Module, Provider, Type } from '@nestjs/common';
import { TenantContextService } from './tenant-context.service.js';
import {
  TenantContextMiddleware,
  ITenantFinder,
  TENANT_FINDER,
  TenantMiddlewareOptions,
} from './tenant-context.middleware.js';
import { TenantGuard } from './tenant.guard.js';

/**
 * 租户模块配置选项
 */
export interface TenantModuleOptions {
  /**
   * 租户查找器类 (用 useClass 创建新实例)
   */
  tenantFinder?: Type<ITenantFinder>;
  /**
   * 使用已存在的租户查找器 (用 useExisting 复用已注册的实例)
   * 当 tenantFinder 需要依赖注入其他服务时使用此选项
   */
  tenantFinderExisting?: Type<ITenantFinder>;
  /**
   * 使用外部提供的 TENANT_FINDER
   * 当此选项为 true 时，必须在其他模块中提供 TENANT_FINDER token
   * 且该模块必须在 AppModule 中先于 TenantContextModule 导入
   */
  useExternalFinder?: boolean;
  /**
   * 导入的模块 (当使用 tenantFinderExisting 时需要导入提供该服务的模块)
   */
  imports?: any[];
  /**
   * 中间件选项
   */
  middlewareOptions?: TenantMiddlewareOptions;
  /**
   * 是否全局注册
   */
  isGlobal?: boolean;
}

/**
 * 租户模块异步配置选项 (返回 TenantModuleOptions)
 */
export interface TenantModuleAsyncOptions {
  /**
   * 导入的模块
   */
  imports?: any[];
  /**
   * 注入的依赖
   */
  inject?: any[];
  /**
   * 工厂函数
   */
  useFactory: (...args: any[]) => Promise<TenantModuleOptions> | TenantModuleOptions;
  /**
   * 是否全局注册
   */
  isGlobal?: boolean;
}

/**
 * 租户模块异步配置选项 (直接注入 TenantFinder 实例)
 * 用于 tenantFinder 需要依赖注入其他服务的场景
 */
export interface TenantModuleAsyncOptionsWithFinder {
  /**
   * 导入的模块 (必须包含提供 TenantFinder 的模块)
   */
  imports: any[];
  /**
   * 注入的依赖 (必须包含 TenantFinder 类)
   */
  inject: any[];
  /**
   * 工厂函数 (第一个注入的依赖应该是 TenantFinder 实例)
   */
  useFactory: (tenantFinder: ITenantFinder, ...args: any[]) => Promise<TenantMiddlewareOptions> | TenantMiddlewareOptions;
  /**
   * 是否全局注册
   */
  isGlobal?: boolean;
}

/**
 * 租户上下文模块
 *
 * @example
 * // 同步注册
 * TenantContextModule.forRoot({
 *   tenantFinder: TenantFinderService,
 *   middlewareOptions: { allowDefaultTenant: true, defaultTenantId: 'xxx' },
 *   isGlobal: true,
 * })
 *
 * @example
 * // 异步注册
 * TenantContextModule.forRootAsync({
 *   imports: [ConfigModule],
 *   inject: [ConfigService],
 *   useFactory: (config: ConfigService) => ({
 *     tenantFinder: TenantFinderService,
 *     middlewareOptions: {
 *       allowDefaultTenant: config.get('ALLOW_DEFAULT_TENANT') === 'true',
 *       defaultTenantId: config.get('DEFAULT_TENANT_ID'),
 *     },
 *   }),
 *   isGlobal: true,
 * })
 */
@Module({})
export class TenantContextModule {
  /**
   * 同步注册租户模块
   */
  static forRoot(options: TenantModuleOptions): DynamicModule {
    const providers: Provider[] = [
      TenantContextService,
      TenantGuard,
      {
        provide: 'TENANT_MIDDLEWARE_OPTIONS',
        useValue: options.middlewareOptions || {},
      },
      {
        provide: TenantContextMiddleware,
        useFactory: (
          tenantContext: TenantContextService,
          tenantFinder: ITenantFinder,
          middlewareOptions: TenantMiddlewareOptions,
        ) => new TenantContextMiddleware(tenantContext, tenantFinder, middlewareOptions),
        inject: [TenantContextService, TENANT_FINDER, 'TENANT_MIDDLEWARE_OPTIONS'],
      },
    ];

    // 构建 exports 列表
    const exports: any[] = [TenantContextService, TenantGuard, TenantContextMiddleware];

    // 如果不使用外部 finder，则自己提供并导出 TENANT_FINDER
    if (!options.useExternalFinder) {
      const tenantFinderProvider: Provider = options.tenantFinderExisting
        ? {
            provide: TENANT_FINDER,
            useExisting: options.tenantFinderExisting,
          }
        : {
            provide: TENANT_FINDER,
            useClass: options.tenantFinder!,
          };
      providers.push(tenantFinderProvider);
      exports.push(TENANT_FINDER);
    }

    return {
      module: TenantContextModule,
      imports: options.imports || [],
      providers,
      exports,
      global: options.isGlobal ?? true,
    };
  }

  /**
   * 异步注册租户模块
   */
  static forRootAsync(options: TenantModuleAsyncOptions): DynamicModule {
    const providers: Provider[] = [
      TenantContextService,
      TenantGuard,
      {
        provide: 'TENANT_MODULE_OPTIONS',
        useFactory: options.useFactory,
        inject: options.inject || [],
      },
      {
        provide: TENANT_FINDER,
        useFactory: async (moduleOptions: TenantModuleOptions) => {
          // 动态实例化租户查找器
          if (!moduleOptions.tenantFinder) {
            throw new Error('tenantFinder is required in async configuration');
          }
          return new moduleOptions.tenantFinder();
        },
        inject: ['TENANT_MODULE_OPTIONS'],
      },
      {
        provide: 'TENANT_MIDDLEWARE_OPTIONS',
        useFactory: (moduleOptions: TenantModuleOptions) =>
          moduleOptions.middlewareOptions || {},
        inject: ['TENANT_MODULE_OPTIONS'],
      },
      {
        provide: TenantContextMiddleware,
        useFactory: (
          tenantContext: TenantContextService,
          tenantFinder: ITenantFinder,
          middlewareOptions: TenantMiddlewareOptions,
        ) => new TenantContextMiddleware(tenantContext, tenantFinder, middlewareOptions),
        inject: [TenantContextService, TENANT_FINDER, 'TENANT_MIDDLEWARE_OPTIONS'],
      },
    ];

    return {
      module: TenantContextModule,
      imports: options.imports || [],
      providers,
      exports: [TenantContextService, TenantGuard, TenantContextMiddleware, TENANT_FINDER],
      global: options.isGlobal ?? true,
    };
  }

  /**
   * 异步注册租户模块 (直接注入 TenantFinder 实例)
   * 用于 TenantFinder 需要依赖注入其他服务 (如 Repository) 的场景
   *
   * @example
   * TenantContextModule.forRootAsyncWithFinder({
   *   imports: [TenantModule],
   *   inject: [TenantFinderService],
   *   useFactory: (tenantFinder) => ({
   *     allowDefaultTenant: true,
   *     defaultTenantId: DEFAULT_TENANT_ID,
   *   }),
   *   isGlobal: true,
   * })
   */
  static forRootAsyncWithFinder(options: TenantModuleAsyncOptionsWithFinder): DynamicModule {
    const providers: Provider[] = [
      TenantContextService,
      TenantGuard,
      {
        provide: TENANT_FINDER,
        useFactory: (tenantFinder: ITenantFinder) => tenantFinder,
        inject: [options.inject[0]], // 第一个注入项是 TenantFinder
      },
      {
        provide: 'TENANT_MIDDLEWARE_OPTIONS',
        useFactory: options.useFactory,
        inject: options.inject,
      },
      {
        provide: TenantContextMiddleware,
        useFactory: (
          tenantContext: TenantContextService,
          tenantFinder: ITenantFinder,
          middlewareOptions: TenantMiddlewareOptions,
        ) => new TenantContextMiddleware(tenantContext, tenantFinder, middlewareOptions),
        inject: [TenantContextService, TENANT_FINDER, 'TENANT_MIDDLEWARE_OPTIONS'],
      },
    ];

    return {
      module: TenantContextModule,
      imports: options.imports,
      providers,
      exports: [TenantContextService, TenantGuard, TenantContextMiddleware, TENANT_FINDER],
      global: options.isGlobal ?? true,
    };
  }
}
