import { Injectable } from '@nestjs/common';
import { type Escrow as PrismaEscrow } from '@prisma/client';
import { PrismaService } from '@modules/shared';
import { EscrowEntity, type EscrowProps } from '../../domain/entities/escrow.entity';
import { type IEscrowRepository } from '../../domain/repositories/escrow.repository';
import { Money } from '../../domain/value-objects/money.vo';

@Injectable()
export class PrismaEscrowRepository implements IEscrowRepository {
  constructor(private readonly prisma: PrismaService) {}

  async findById(id: string): Promise<EscrowEntity | null> {
    const escrow = await this.prisma.escrow.findUnique({ where: { id } });
    return escrow ? this.toDomain(escrow) : null;
  }

  async findByOrderId(orderId: string): Promise<EscrowEntity | null> {
    const escrow = await this.prisma.escrow.findUnique({
      where: { orderId },
    });
    return escrow ? this.toDomain(escrow) : null;
  }

  async save(entity: EscrowEntity): Promise<void> {
    await this.prisma.escrow.create({
      data: {
        id: entity.id,
        orderId: entity.orderId,
        amountVND: entity.amount.value,
        feeVND: entity.fee.value,
        status: entity.status,
        heldAt: entity.heldAt,
        releasedAt: entity.releasedAt,
        disputeReason: entity.disputeReason,
        disputedAt: entity.disputedAt,
      },
    });
  }

  async update(entity: EscrowEntity): Promise<void> {
    await this.prisma.escrow.update({
      where: { id: entity.id },
      data: {
        status: entity.status,
        heldAt: entity.heldAt,
        releasedAt: entity.releasedAt,
        disputeReason: entity.disputeReason,
        disputedAt: entity.disputedAt,
      },
    });
  }

  private toDomain(raw: PrismaEscrow): EscrowEntity {
    const amount = Money.create(raw.amountVND).unwrap();
    const fee = Money.create(raw.feeVND).unwrap();

    const props: EscrowProps = {
      orderId: raw.orderId,
      amount,
      fee,
      status: raw.status,
      heldAt: raw.heldAt,
      releasedAt: raw.releasedAt,
      disputeReason: raw.disputeReason,
      disputedAt: raw.disputedAt,
    };

    return new EscrowEntity(raw.id, props, raw.createdAt, raw.updatedAt);
  }
}
