import { describe, it, expect } from 'vitest';
import { OrderEntity } from '../entities/order.entity';
import { OrderCancelledEvent } from '../events/order-cancelled.event';
import { OrderCreatedEvent } from '../events/order-created.event';
import { OrderPaidEvent } from '../events/order-paid.event';
import { Money } from '../value-objects/money.vo';
import { PlatformFee } from '../value-objects/platform-fee.vo';

describe('OrderEntity', () => {
  const createOrder = () => {
    const amount = Money.create(5_000_000_000n).unwrap();
    const fee = PlatformFee.fromOrderAmount(5_000_000_000n).unwrap();
    const payout = Money.create(5_000_000_000n - fee.value).unwrap();
    return OrderEntity.createNew(
      'ord-1',
      'buyer-1',
      'seller-1',
      'listing-1',
      amount,
      fee,
      payout,
      'idem-key-1',
    );
  };

  it('should create a new order with CREATED status and emit event', () => {
    const order = createOrder();

    expect(order.id).toBe('ord-1');
    expect(order.buyerId).toBe('buyer-1');
    expect(order.sellerId).toBe('seller-1');
    expect(order.listingId).toBe('listing-1');
    expect(order.status).toBe('CREATED');
    expect(order.amount.value).toBe(5_000_000_000n);
    expect(order.platformFee.value).toBe(250_000_000n); // 5%
    expect(order.sellerPayout.value).toBe(4_750_000_000n);
    expect(order.idempotencyKey).toBe('idem-key-1');

    const events = order.domainEvents;
    expect(events).toHaveLength(1);
    expect(events[0]).toBeInstanceOf(OrderCreatedEvent);
  });

  it('should transition CREATED → PAYMENT_PENDING', () => {
    const order = createOrder();
    const result = order.markPaymentPending();
    expect(result.isOk).toBe(true);
    expect(order.status).toBe('PAYMENT_PENDING');
  });

  it('should transition PAYMENT_PENDING → PAYMENT_CONFIRMED with event', () => {
    const order = createOrder();
    order.markPaymentPending();
    order.clearDomainEvents();

    const result = order.markPaymentConfirmed();
    expect(result.isOk).toBe(true);
    expect(order.status).toBe('PAYMENT_CONFIRMED');

    const events = order.domainEvents;
    expect(events).toHaveLength(1);
    expect(events[0]).toBeInstanceOf(OrderPaidEvent);
  });

  it('should transition PAYMENT_CONFIRMED → ESCROW_HELD', () => {
    const order = createOrder();
    order.markPaymentPending();
    order.markPaymentConfirmed();
    const result = order.markEscrowHeld();
    expect(result.isOk).toBe(true);
    expect(order.status).toBe('ESCROW_HELD');
  });

  it('should follow full settlement flow', () => {
    const order = createOrder();
    expect(order.markPaymentPending().isOk).toBe(true);
    expect(order.markPaymentConfirmed().isOk).toBe(true);
    expect(order.markEscrowHeld().isOk).toBe(true);
    expect(order.markShipped().isOk).toBe(true);
    expect(order.markDelivered().isOk).toBe(true);
    expect(order.markEscrowReleased().isOk).toBe(true);
    expect(order.markCompleted().isOk).toBe(true);
    expect(order.status).toBe('COMPLETED');
  });

  it('should allow cancellation from CREATED', () => {
    const order = createOrder();
    order.clearDomainEvents();
    const result = order.markCancelled();
    expect(result.isOk).toBe(true);
    expect(order.status).toBe('CANCELLED');

    const events = order.domainEvents;
    expect(events).toHaveLength(1);
    expect(events[0]).toBeInstanceOf(OrderCancelledEvent);
  });

  it('should allow cancellation from PAYMENT_PENDING', () => {
    const order = createOrder();
    order.markPaymentPending();
    const result = order.markCancelled();
    expect(result.isOk).toBe(true);
    expect(order.status).toBe('CANCELLED');
  });

  it('should reject invalid status transition', () => {
    const order = createOrder();
    // Cannot go directly from CREATED to COMPLETED
    const result = order.markCompleted();
    expect(result.isErr).toBe(true);
    expect(result.unwrapErr().message).toContain('CREATED');
  });

  it('should reject cancellation from COMPLETED', () => {
    const order = createOrder();
    order.markPaymentPending();
    order.markPaymentConfirmed();
    order.markEscrowHeld();
    order.markShipped();
    order.markDelivered();
    order.markEscrowReleased();
    order.markCompleted();

    const result = order.markCancelled();
    expect(result.isErr).toBe(true);
  });

  it('should transition to dispute from ESCROW_HELD', () => {
    const order = createOrder();
    order.markPaymentPending();
    order.markPaymentConfirmed();
    order.markEscrowHeld();
    const result = order.markDispute();
    expect(result.isOk).toBe(true);
    expect(order.status).toBe('DISPUTE');
  });

  it('should allow refund from DISPUTE', () => {
    const order = createOrder();
    order.markPaymentPending();
    order.markPaymentConfirmed();
    order.markEscrowHeld();
    order.markDispute();
    const result = order.markRefunded();
    expect(result.isOk).toBe(true);
    expect(order.status).toBe('REFUNDED');
  });
});
