import { ILike, Repository } from 'typeorm';
import { ITokenRepository } from '../../../domain/repositories/token-repository';
import { PaginationOptions } from '../../../domain/repositories/pagination-options';
import { Token } from '../../../domain/entities/token';
import { TokenEntity } from '../entities/token.entity';
import { AppDataSource } from '../data-source';
import { tokenMapper } from './mappers/token.mapper';

export class TypeOrmTokenRepository implements ITokenRepository {
  private get repository(): Repository<TokenEntity> {
    return AppDataSource.getRepository(TokenEntity);
  }

  async findById(id: string): Promise<Token | null> {
    const entity = await this.repository.findOneBy({ id });
    return entity ? tokenMapper.toDomain(entity) : null;
  }

  async findBySymbol(symbol: string): Promise<Token | null> {
    const entity = await this.repository.findOneBy({ symbol });
    return entity ? tokenMapper.toDomain(entity) : null;
  }

  async findByNetworkId(networkId: string): Promise<Token[]> {
    const entities = await this.repository.find({
      where: { networkId },
      order: { createdAt: 'DESC' },
    });
    return entities.map(tokenMapper.toDomain);
  }

  async findByCode(code: string): Promise<Token | null> {
    const entity = await this.repository.findOneBy({ code });
    return entity ? tokenMapper.toDomain(entity) : null;
  }

  async findByAddressAndNetworkId(address: string, networkId: string): Promise<Token | null> {
    const entity = await this.repository.findOneBy({
      address: ILike(address),
      networkId,
    });
    return entity ? tokenMapper.toDomain(entity) : null;
  }

  async findActive(options?: PaginationOptions): Promise<Token[]> {
    const entities = await this.repository.find({
      where: { isActive: true },
      take: options?.limit,
      skip: options?.offset,
      order: { createdAt: 'DESC' },
    });
    return entities.map(tokenMapper.toDomain);
  }

  async findAll(options?: PaginationOptions): Promise<Token[]> {
    const entities = await this.repository.find({
      take: options?.limit,
      skip: options?.offset,
      order: { createdAt: 'DESC' },
    });
    return entities.map(tokenMapper.toDomain);
  }

  async save(token: Token): Promise<Token> {
    const entity = await this.repository.save(tokenMapper.toEntity(token));
    return tokenMapper.toDomain(entity);
  }

  async update(token: Token): Promise<Token> {
    const entity = await this.repository.save(tokenMapper.toEntity(token));
    return tokenMapper.toDomain(entity);
  }

  async delete(id: string): Promise<void> {
    await this.repository.delete(id);
  }
}
