import {
  EntityTarget,
  FindManyOptions,
  QueryRunner,
  Repository,
} from 'typeorm';

export abstract class BaseDataService<Entity> {
  constructor(private repository: Repository<Entity>) {}

  getRepository(): Repository<Entity> {
    return this.repository;
  }

  async create(
    queryRunner: QueryRunner,
    entityTarget: EntityTarget<Entity>,
    entity: Entity,
  ): Promise<Entity> {
    // const newEntity = this.repository.create(entityTarget, entity);
    return await this.repository.save(entity);
  }

  async createMany(
    queryRunner: QueryRunner,
    entityTarget: EntityTarget<Entity>,
    entity: Entity[],
  ): Promise<Entity[]> {
    // const newEntity = this.repository.create(entityTarget, entity);
    return await this.repository.save(entity);
  }

  async createBatch(
    queryRunner: QueryRunner,
    entityTarget: EntityTarget<Entity>,
    entity: Entity[],
  ): Promise<Entity[]> {
    // const newEntity = this.repository.create(entityTarget, entity);
    return await this.repository.save(entity);
  }

  async update(
    queryRunner: QueryRunner,
    entityTarget: EntityTarget<Entity>,
    filterUpdate: any,
    entity: Entity,
  ): Promise<Entity> {
    const newEntity = await this.repository.findOne({
      where: filterUpdate,
    });

    if (!newEntity) throw new Error('Data not found!');
    Object.assign(newEntity, entity);
    return await this.repository.save(newEntity);
  }

  async deleteById(
    queryRunner: QueryRunner,
    entityTarget: EntityTarget<Entity>,
    id: string,
  ): Promise<void> {
    await this.repository.delete(id);
  }

  async deleteByIds(
    queryRunner: QueryRunner,
    entityTarget: EntityTarget<Entity>,
    ids: string[],
  ): Promise<void> {
    await this.repository.delete(ids);
  }

  async deleteByOptions(
    queryRunner: QueryRunner,
    entityTarget: EntityTarget<Entity>,
    findManyOptions: FindManyOptions<Entity>,
  ): Promise<void> {
    const datas = await this.repository.find(findManyOptions);
    await this.repository.delete(datas?.map((item) => item['id']));
  }

  async getOneByOptions(findOneOptions): Promise<Entity> {
    return await this.repository.findOne(findOneOptions);
  }

  async getManyByOptions(findOneOptions): Promise<Entity[]> {
    return await this.repository.find(findOneOptions);
  }
}
