import { Repository, SelectQueryBuilder, FindOptionsWhere, DeepPartial } from 'typeorm';
import { TenantContextService } from './tenant-context.service.js';

/**
 * 带 tenant_id 的 ORM 实体接口
 */
export interface TenantAwareEntity {
  tenantId: string;
}

/**
 * 租户感知基础仓库
 * 所有需要租户隔离的仓库都应继承此类
 *
 * @template _TEntity - 领域实体类型 (供子类使用)
 * @template TORM - ORM 实体类型 (必须包含 tenantId)
 */
export abstract class BaseTenantRepository<_TEntity, TORM extends TenantAwareEntity> {
  constructor(
    protected readonly repo: Repository<TORM>,
    protected readonly tenantContext: TenantContextService,
  ) {}

  /**
   * 获取当前租户 ID
   * 如果租户上下文不存在则抛出异常
   */
  protected getTenantId(): string {
    return this.tenantContext.requireTenantId();
  }

  /**
   * 尝试获取租户 ID (可能为 undefined)
   * 用于可选租户场景
   */
  protected tryGetTenantId(): string | undefined {
    return this.tenantContext.getCurrentTenantId();
  }

  /**
   * 创建带租户过滤的 QueryBuilder
   */
  protected createTenantQueryBuilder(alias: string): SelectQueryBuilder<TORM> {
    return this.repo
      .createQueryBuilder(alias)
      .where(`${alias}.tenant_id = :tenantId`, { tenantId: this.getTenantId() });
  }

  /**
   * 查找单个实体 (自动添加租户过滤)
   */
  protected async findOneWithTenant(
    where: Omit<FindOptionsWhere<TORM>, 'tenantId'>,
  ): Promise<TORM | null> {
    return this.repo.findOne({
      where: {
        ...where,
        tenantId: this.getTenantId(),
      } as FindOptionsWhere<TORM>,
    });
  }

  /**
   * 查找多个实体 (自动添加租户过滤)
   */
  protected async findWithTenant(
    where: Omit<FindOptionsWhere<TORM>, 'tenantId'>,
  ): Promise<TORM[]> {
    return this.repo.find({
      where: {
        ...where,
        tenantId: this.getTenantId(),
      } as FindOptionsWhere<TORM>,
    });
  }

  /**
   * 保存实体 (自动设置租户 ID)
   */
  protected async saveWithTenant(entity: Omit<DeepPartial<TORM>, 'tenantId'>): Promise<TORM> {
    const entityWithTenant = {
      ...entity,
      tenantId: this.getTenantId(),
    } as DeepPartial<TORM>;
    return this.repo.save(entityWithTenant);
  }

  /**
   * 批量保存实体 (自动设置租户 ID)
   */
  protected async saveManyWithTenant(
    entities: Array<Omit<DeepPartial<TORM>, 'tenantId'>>,
  ): Promise<TORM[]> {
    const tenantId = this.getTenantId();
    const entitiesWithTenant = entities.map((entity) => ({
      ...entity,
      tenantId,
    })) as DeepPartial<TORM>[];
    return this.repo.save(entitiesWithTenant);
  }

  /**
   * 统计符合条件的实体数量 (自动添加租户过滤)
   */
  protected async countWithTenant(
    where?: Omit<FindOptionsWhere<TORM>, 'tenantId'>,
  ): Promise<number> {
    return this.repo.count({
      where: {
        ...(where || {}),
        tenantId: this.getTenantId(),
      } as FindOptionsWhere<TORM>,
    });
  }

  /**
   * 更新实体 (确保只更新当前租户的数据)
   */
  protected async updateWithTenant(
    id: string,
    partial: Partial<Omit<TORM, 'tenantId' | 'id'>>,
  ): Promise<void> {
    await this.repo
      .createQueryBuilder()
      .update()
      .set(partial as any)
      .where('id = :id', { id })
      .andWhere('tenant_id = :tenantId', { tenantId: this.getTenantId() })
      .execute();
  }

  /**
   * 软删除实体 (确保只删除当前租户的数据)
   */
  protected async softDeleteWithTenant(id: string): Promise<void> {
    await this.repo
      .createQueryBuilder()
      .softDelete()
      .where('id = :id', { id })
      .andWhere('tenant_id = :tenantId', { tenantId: this.getTenantId() })
      .execute();
  }

  /**
   * 硬删除实体 (确保只删除当前租户的数据)
   */
  protected async deleteWithTenant(id: string): Promise<void> {
    await this.repo
      .createQueryBuilder()
      .delete()
      .where('id = :id', { id })
      .andWhere('tenant_id = :tenantId', { tenantId: this.getTenantId() })
      .execute();
  }

  /**
   * 检查实体是否存在于当前租户
   */
  protected async existsInTenant(id: string): Promise<boolean> {
    const count = await this.repo
      .createQueryBuilder()
      .where('id = :id', { id })
      .andWhere('tenant_id = :tenantId', { tenantId: this.getTenantId() })
      .getCount();
    return count > 0;
  }
}
