import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { MonitoredAddressMapper } from '../mappers/monitored-address.mapper';
import { IMonitoredAddressRepository } from '@/domain/repositories/monitored-address.repository.interface';
import { MonitoredAddress } from '@/domain/aggregates/monitored-address';
import { ChainType, EvmAddress } from '@/domain/value-objects';

@Injectable()
export class MonitoredAddressRepositoryImpl implements IMonitoredAddressRepository {
  constructor(private readonly prisma: PrismaService) {}

  async save(address: MonitoredAddress): Promise<MonitoredAddress> {
    const data = MonitoredAddressMapper.toPersistence(address);

    if (address.id) {
      const updated = await this.prisma.monitoredAddress.update({
        where: { id: address.id },
        data,
      });
      return MonitoredAddressMapper.toDomain(updated);
    } else {
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      const { id: _, ...createData } = data;
      const created = await this.prisma.monitoredAddress.create({
        data: createData,
      });
      return MonitoredAddressMapper.toDomain(created);
    }
  }

  async findById(id: bigint): Promise<MonitoredAddress | null> {
    const record = await this.prisma.monitoredAddress.findUnique({
      where: { id },
    });
    return record ? MonitoredAddressMapper.toDomain(record) : null;
  }

  async findByChainAndAddress(
    chainType: ChainType,
    address: EvmAddress,
  ): Promise<MonitoredAddress | null> {
    const record = await this.prisma.monitoredAddress.findUnique({
      where: {
        uk_chain_address: {
          chainType: chainType.toString(),
          address: address.lowercase,
        },
      },
    });
    return record ? MonitoredAddressMapper.toDomain(record) : null;
  }

  async findActiveByChain(chainType: ChainType): Promise<MonitoredAddress[]> {
    const records = await this.prisma.monitoredAddress.findMany({
      where: {
        chainType: chainType.toString(),
        isActive: true,
      },
    });
    return records.map(MonitoredAddressMapper.toDomain);
  }

  async findByUserId(userId: bigint): Promise<MonitoredAddress[]> {
    const records = await this.prisma.monitoredAddress.findMany({
      where: { userId },
    });
    return records.map(MonitoredAddressMapper.toDomain);
  }

  async existsByChainAndAddress(chainType: ChainType, address: EvmAddress): Promise<boolean> {
    const count = await this.prisma.monitoredAddress.count({
      where: {
        chainType: chainType.toString(),
        address: address.lowercase,
      },
    });
    return count > 0;
  }

  async getAllActiveAddresses(chainType: ChainType): Promise<string[]> {
    const records = await this.prisma.monitoredAddress.findMany({
      where: {
        chainType: chainType.toString(),
        isActive: true,
      },
      select: { address: true },
    });
    return records.map((r) => r.address.toLowerCase());
  }
}
