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

export interface CancelOrderResult {
  orderId: string;
  status: string;
}

@CommandHandler(CancelOrderCommand)
export class CancelOrderHandler implements ICommandHandler<CancelOrderCommand> {
  constructor(
    @Inject(ORDER_REPOSITORY) private readonly orderRepo: IOrderRepository,
    private readonly eventBus: EventBus,
    private readonly logger: LoggerService,
  ) {}

  async execute(command: CancelOrderCommand): Promise<CancelOrderResult> {
    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,
        );
      }

      // Only buyer or seller can cancel
      if (order.buyerId !== command.userId && order.sellerId !== command.userId) {
        throw new DomainException(
          ErrorCode.FORBIDDEN,
          'Bạn không có quyền hủy đơn hàng này',
          HttpStatus.FORBIDDEN,
        );
      }

      const result = order.markCancelled();
      if (result.isErr) throw result.unwrapErr();

      await this.orderRepo.update(order);

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

      this.logger.log(
        `Order cancelled: id=${command.orderId}, by=${command.userId}, reason=${command.reason}`,
        'CancelOrderHandler',
      );

      return { orderId: order.id, status: order.status };
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to cancel order: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined,
        this.constructor.name,
      );
      throw new InternalServerErrorException('Không thể hủy đơn hàng. Vui lòng thử lại sau');
    }
  }
}
