import {
  DeepPartial,
  FindManyOptions,
  FindOneOptions,
  FindOptionsWhere,
  ObjectLiteral,
  Repository,
} from "typeorm";

export abstract class BaseRepository<T extends ObjectLiteral> {
  protected constructor(protected readonly repository: Repository<T>) {}

  /** Find a single entity by its primary key. */
  async findById(
    id: string,
    options?: Omit<FindOneOptions<T>, "where">,
  ): Promise<T | null> {
    return this.repository.findOne({
      ...options,
      where: { id } as unknown as FindOptionsWhere<T>,
    });
  }

  /** Find many entities matching the given options. */
  async findAll(options?: FindManyOptions<T>): Promise<T[]> {
    return this.repository.find(options);
  }

  /** Find many entities + return the total count for pagination. */
  async findAndCount(options?: FindManyOptions<T>): Promise<[T[], number]> {
    return this.repository.findAndCount(options);
  }

  /** Create and persist a new entity. */
  async create(data: DeepPartial<T>): Promise<T> {
    const entity = this.repository.create(data);
    return this.repository.save(entity);
  }

  /** Patch an entity in place and return the reloaded row. */
  async update(id: string, data: DeepPartial<T>): Promise<T | null> {
    await this.repository.update(id, data as never);
    return this.findById(id);
  }

  /** Soft-delete an entity by primary key (sets deleted_at). */
  async softDelete(id: string): Promise<void> {
    await this.repository.softDelete(id);
  }

  /** Permanently delete an entity. Avoid in domain code; prefer softDelete. */
  async hardDelete(id: string): Promise<void> {
    await this.repository.delete(id);
  }
}
