import { Injectable } from '@nestjs/common';
import { PrismaService } from '@/infrastructure/persistence/prisma/prisma.service';
import { ISettlementOrderRepository } from '@/domain/repositories';
import { SettlementOrder } from '@/domain/aggregates';
import { SettlementStatus } from '@/domain/value-objects';
import Decimal from 'decimal.js';

@Injectable()
export class SettlementOrderRepositoryImpl implements ISettlementOrderRepository {
  constructor(private readonly prisma: PrismaService) {}

  async save(order: SettlementOrder): Promise<SettlementOrder> {
    const data = {
      userId: order.userId.value,
      usdtAmount: order.usdtAmount.toDecimal(),
      settleCurrency: order.settleCurrency,
      swapTxHash: order.swapTxHash,
      receivedAmount: order.receivedAmount?.toDecimal() ?? null,
      status: order.status,
      settledAt: order.settledAt,
    };

    if (order.id === BigInt(0)) {
      const created = await this.prisma.settlementOrder.create({ data });
      return this.toDomain(created);
    } else {
      const updated = await this.prisma.settlementOrder.update({
        where: { id: order.id },
        data,
      });
      return this.toDomain(updated);
    }
  }

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

  async findByUserId(userId: bigint, status?: SettlementStatus): Promise<SettlementOrder[]> {
    const where: Record<string, unknown> = { userId };
    if (status) {
      where.status = status;
    }

    const records = await this.prisma.settlementOrder.findMany({
      where,
      orderBy: { createdAt: 'desc' },
    });
    return records.map(r => this.toDomain(r));
  }

  async findPendingOrders(): Promise<SettlementOrder[]> {
    const records = await this.prisma.settlementOrder.findMany({
      where: {
        status: { in: [SettlementStatus.PENDING, SettlementStatus.SWAPPING] },
      },
      orderBy: { createdAt: 'asc' },
    });
    return records.map(r => this.toDomain(r));
  }

  private toDomain(record: {
    id: bigint;
    userId: bigint;
    usdtAmount: Decimal;
    settleCurrency: string;
    swapTxHash: string | null;
    receivedAmount: Decimal | null;
    status: string;
    settledAt: Date | null;
    createdAt: Date;
  }): SettlementOrder {
    return SettlementOrder.reconstruct({
      id: record.id,
      userId: record.userId,
      usdtAmount: new Decimal(record.usdtAmount.toString()),
      settleCurrency: record.settleCurrency,
      swapTxHash: record.swapTxHash,
      receivedAmount: record.receivedAmount ? new Decimal(record.receivedAmount.toString()) : null,
      status: record.status,
      settledAt: record.settledAt,
      createdAt: record.createdAt,
    });
  }
}
