import { Repository } from 'typeorm';
import { IAddressRepository } from '../../../domain/repositories/address-repository';
import { Address } from '../../../domain/entities/address';
import { AddressEntity } from '../entities/address.entity';
import { AppDataSource } from '../data-source';
import { addressMapper } from './mappers/address.mapper';

export class TypeOrmAddressRepository implements IAddressRepository {
  private get repository(): Repository<AddressEntity> {
    return AppDataSource.getRepository(AddressEntity);
  }

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

  async findByIds(ids: string[]): Promise<Address[]> {
    if (ids.length === 0) {
      return [];
    }
    const entities = await this.repository
      .createQueryBuilder('address')
      .where('address.id IN (:...ids)', { ids })
      .getMany();
    return entities.map(addressMapper.toDomain);
  }

  async findByWalletId(walletId: string): Promise<Address[]> {
    const entities = await this.repository.find({
      where: { walletId },
      order: { createdAt: 'DESC' },
    });
    return entities.map(addressMapper.toDomain);
  }

  async findByWalletIdAndType(walletId: string, type: string): Promise<Address[]> {
    const entities = await this.repository.find({
      where: { walletId, type },
      order: { createdAt: 'DESC' },
    });
    return entities.map(addressMapper.toDomain);
  }

  async findByAddress(address: string): Promise<Address | null> {
    const isEvm = address.toLowerCase().startsWith('0x');

    if (!isEvm) {
      const entity = await this.repository.findOneBy({ address });
      return entity ? addressMapper.toDomain(entity) : null;
    }

    const entity = await this.repository
      .createQueryBuilder('address')
      .where('LOWER(address.address) = LOWER(:address)', { address })
      .getOne();
    return entity ? addressMapper.toDomain(entity) : null;
  }

  async save(address: Address): Promise<Address> {
    const entity = await this.repository.save(addressMapper.toEntity(address));
    return addressMapper.toDomain(entity);
  }

  async update(address: Address): Promise<Address> {
    const entity = await this.repository.save(addressMapper.toEntity(address));
    return addressMapper.toDomain(entity);
  }

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