import { HttpStatus, Inject, InternalServerErrorException } from '@nestjs/common';
import { CommandHandler, EventBus, type ICommandHandler } from '@nestjs/cqrs';
import { DomainException, ErrorCode, LoggerService } from '@modules/shared';
import { ESCROW_REPOSITORY, type IEscrowRepository } from '../../../domain/repositories/escrow.repository';
import { ORDER_REPOSITORY, type IOrderRepository } from '../../../domain/repositories/order.repository';
import { ReleaseEscrowCommand } from './release-escrow.command';

export interface ReleaseEscrowResult {
  escrowId: string;
  status: string;
  payoutVND: string;
  releasedAt: string;
}

@CommandHandler(ReleaseEscrowCommand)
export class ReleaseEscrowHandler implements ICommandHandler<ReleaseEscrowCommand> {
  constructor(
    @Inject(ORDER_REPOSITORY) private readonly orderRepo: IOrderRepository,
    @Inject(ESCROW_REPOSITORY) private readonly escrowRepo: IEscrowRepository,
    private readonly eventBus: EventBus,
    private readonly logger: LoggerService,
  ) {}

  async execute(command: ReleaseEscrowCommand): Promise<ReleaseEscrowResult> {
    try {
      const order = await this.orderRepo.findById(command.orderId);
      if (!order) {
        throw new DomainException(ErrorCode.ORDER_NOT_FOUND, 'Đơn hàng không tồn tại', HttpStatus.NOT_FOUND);
      }

      const escrow = await this.escrowRepo.findByOrderId(command.orderId);
      if (!escrow) {
        throw new DomainException(ErrorCode.ESCROW_NOT_FOUND, 'Ký quỹ không tồn tại', HttpStatus.NOT_FOUND);
      }

      // Release escrow
      const releaseResult = escrow.release();
      if (releaseResult.isErr) throw releaseResult.unwrapErr();

      // Transition order
      const orderResult = order.markEscrowReleased();
      if (orderResult.isErr) throw orderResult.unwrapErr();

      await this.escrowRepo.update(escrow);
      await this.orderRepo.update(order);

      for (const event of escrow.clearDomainEvents()) {
        this.eventBus.publish(event);
      }

      this.logger.log(
        `Escrow released: id=${escrow.id}, order=${command.orderId}, payout=${escrow.netPayout}`,
        'ReleaseEscrowHandler',
      );

      return {
        escrowId: escrow.id,
        status: escrow.status,
        payoutVND: escrow.netPayout.toString(),
        releasedAt: escrow.releasedAt?.toISOString() ?? '',
      };
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to release escrow: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined,
        this.constructor.name,
      );
      throw new InternalServerErrorException('Không thể giải phóng ký quỹ. Vui lòng thử lại sau');
    }
  }
}
