import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { DepositTransactionMapper } from '../mappers/deposit-transaction.mapper';
import { IDepositTransactionRepository } from '@/domain/repositories/deposit-transaction.repository.interface';
import { DepositTransaction } from '@/domain/aggregates/deposit-transaction';
import { ChainType, TxHash } from '@/domain/value-objects';
import { DepositStatus } from '@/domain/enums';

@Injectable()
export class DepositTransactionRepositoryImpl implements IDepositTransactionRepository {
  constructor(private readonly prisma: PrismaService) {}

  async save(deposit: DepositTransaction): Promise<DepositTransaction> {
    const data = DepositTransactionMapper.toPersistence(deposit);

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

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

  async findByTxHash(txHash: TxHash): Promise<DepositTransaction | null> {
    const record = await this.prisma.depositTransaction.findUnique({
      where: { txHash: txHash.toString() },
    });
    return record ? DepositTransactionMapper.toDomain(record) : null;
  }

  async findByStatus(chainType: ChainType, status: DepositStatus): Promise<DepositTransaction[]> {
    const records = await this.prisma.depositTransaction.findMany({
      where: {
        chainType: chainType.toString(),
        status,
      },
      orderBy: { blockNumber: 'asc' },
    });
    return records.map(DepositTransactionMapper.toDomain);
  }

  async findPendingConfirmation(chainType: ChainType): Promise<DepositTransaction[]> {
    const records = await this.prisma.depositTransaction.findMany({
      where: {
        chainType: chainType.toString(),
        status: {
          in: [DepositStatus.DETECTED, DepositStatus.CONFIRMING],
        },
      },
      orderBy: { blockNumber: 'asc' },
    });
    return records.map(DepositTransactionMapper.toDomain);
  }

  async findPendingNotification(): Promise<DepositTransaction[]> {
    const records = await this.prisma.depositTransaction.findMany({
      where: {
        status: DepositStatus.CONFIRMED,
        notifiedAt: null,
      },
      orderBy: { createdAt: 'asc' },
      take: 100,
    });
    return records.map(DepositTransactionMapper.toDomain);
  }

  async findByUserId(userId: bigint, limit: number = 50): Promise<DepositTransaction[]> {
    const records = await this.prisma.depositTransaction.findMany({
      where: { userId },
      orderBy: { createdAt: 'desc' },
      take: limit,
    });
    return records.map(DepositTransactionMapper.toDomain);
  }

  async existsByTxHash(txHash: TxHash): Promise<boolean> {
    const count = await this.prisma.depositTransaction.count({
      where: { txHash: txHash.toString() },
    });
    return count > 0;
  }
}
