import { Injectable, Logger, Inject, BadRequestException, NotFoundException } from '@nestjs/common';
import {
  TransferOrder,
  CreateTransferOrderParams,
} from '../../domain/aggregates/transfer-order.aggregate';
import {
  ITransferOrderRepository,
  TRANSFER_ORDER_REPOSITORY,
} from '../../domain/repositories/transfer-order.repository.interface';
import { TransferFeeDomainService } from '../../domain/services/transfer-fee.service';
import { TransferOrderStatus, CANCELLABLE_STATUSES } from '../../domain/value-objects/transfer-order-status.enum';
import { UnitOfWork, UNIT_OF_WORK } from '../../infrastructure/persistence/unit-of-work';
import { PlantingServiceClient } from '../../infrastructure/external/planting-service.client';
import { IdentityServiceClient } from '../../infrastructure/external/identity-service.client';
import { WalletServiceClient } from '../../infrastructure/external/wallet-service.client';
import { DomainEvent } from '../../domain/events/domain-event.interface';

@Injectable()
export class TransferApplicationService {
  private readonly logger = new Logger(TransferApplicationService.name);

  constructor(
    @Inject(TRANSFER_ORDER_REPOSITORY)
    private readonly transferOrderRepo: ITransferOrderRepository,
    @Inject(UNIT_OF_WORK)
    private readonly unitOfWork: UnitOfWork,
    private readonly transferFeeService: TransferFeeDomainService,
    private readonly plantingClient: PlantingServiceClient,
    private readonly identityClient: IdentityServiceClient,
    private readonly walletClient: WalletServiceClient,
  ) {}

  /**
   * 发起转让（买方向卖方购买）
   */
  async createTransferOrder(params: {
    buyerUserId: bigint;
    buyerAccountSequence: string;
    sourceOrderNo: string;
    treeCount: number;
    transferPrice: string;
  }): Promise<{ transferOrderNo: string }> {
    this.logger.log(`Creating transfer order: buyer=${params.buyerAccountSequence}, source=${params.sourceOrderNo}, trees=${params.treeCount}`);

    // 1. 查询原订单信息
    const plantingOrder = await this.plantingClient.getPlantingOrder(params.sourceOrderNo);
    if (!plantingOrder) {
      throw new NotFoundException(`认种订单 ${params.sourceOrderNo} 不存在`);
    }

    // 2. 验证订单状态
    if (plantingOrder.status !== 'MINING_ENABLED') {
      throw new BadRequestException(`订单 ${params.sourceOrderNo} 状态不允许转让，当前状态: ${plantingOrder.status}`);
    }

    // 3. 验证可转让棵数
    if (plantingOrder.availableForTransfer < params.treeCount) {
      throw new BadRequestException(
        `可转让棵数不足，可转让: ${plantingOrder.availableForTransfer}，请求: ${params.treeCount}`,
      );
    }

    // 4. 不能自己转给自己
    if (params.buyerUserId === BigInt(plantingOrder.userId)) {
      throw new BadRequestException('不能转让给自己');
    }

    // 5. 验证买方实名认证
    const buyerKyc = await this.identityClient.isKycVerified(params.buyerUserId.toString());
    if (!buyerKyc) {
      throw new BadRequestException('买方尚未完成实名认证');
    }

    // 6. 查询原始算力值
    const contributionInfo = await this.plantingClient.getContributionPerTree(params.sourceOrderNo);

    // 7. 计算费用
    const fees = this.transferFeeService.calculateFees(params.transferPrice);

    // 8. 创建聚合根
    const createParams: CreateTransferOrderParams = {
      sellerUserId: BigInt(plantingOrder.userId),
      sellerAccountSequence: plantingOrder.accountSequence,
      buyerUserId: params.buyerUserId,
      buyerAccountSequence: params.buyerAccountSequence,
      sourceOrderNo: params.sourceOrderNo,
      sourceAdoptionId: BigInt(plantingOrder.id),
      treeCount: params.treeCount,
      contributionPerTree: contributionInfo.contributionPerTree,
      originalAdoptionDate: new Date(contributionInfo.adoptionDate),
      originalExpireDate: new Date(contributionInfo.expireDate),
      selectedProvince: plantingOrder.selectedProvince,
      selectedCity: plantingOrder.selectedCity,
      transferPrice: params.transferPrice,
      platformFeeRate: fees.platformFeeRate,
      platformFeeAmount: fees.platformFeeAmount,
      sellerReceiveAmount: fees.sellerReceiveAmount,
    };

    const order = TransferOrder.create(createParams);

    // 9. 事务保存
    await this.unitOfWork.executeInTransaction(async (uow) => {
      await uow.saveTransferOrder(order);

      // 记录状态日志
      await uow.logStatusChange({
        transferOrderNo: order.transferOrderNo,
        fromStatus: '',
        toStatus: TransferOrderStatus.PENDING,
        fromSagaStep: '',
        toSagaStep: 'INIT',
        operatorType: 'USER',
        operatorId: params.buyerUserId.toString(),
        remark: '买方发起转让',
      });

      // Outbox 事件
      const outboxEvents = order.getDomainEvents().map((e: DomainEvent) => ({
        eventType: e.type,
        topic: this.getTopicForEvent(e.type),
        key: e.aggregateId,
        payload: e.data,
        aggregateId: e.aggregateId,
        aggregateType: e.aggregateType,
      }));
      uow.addOutboxEvents(outboxEvents);
      await uow.commitOutboxEvents();
    });

    order.clearDomainEvents();
    this.logger.log(`Transfer order created: ${order.transferOrderNo}`);

    return { transferOrderNo: order.transferOrderNo };
  }

  /**
   * 卖方确认转让
   */
  async sellerConfirm(transferOrderNo: string, sellerUserId: bigint): Promise<void> {
    this.logger.log(`Seller confirming transfer: ${transferOrderNo}`);

    const order = await this.transferOrderRepo.findByTransferOrderNo(transferOrderNo);
    if (!order) {
      throw new NotFoundException(`转让订单 ${transferOrderNo} 不存在`);
    }

    if (order.sellerUserId !== sellerUserId) {
      throw new BadRequestException('仅卖方可以确认');
    }

    order.sellerConfirm();

    await this.unitOfWork.executeInTransaction(async (uow) => {
      await uow.saveTransferOrder(order);

      await uow.logStatusChange({
        transferOrderNo: order.transferOrderNo,
        fromStatus: TransferOrderStatus.PENDING,
        toStatus: TransferOrderStatus.SELLER_CONFIRMED,
        fromSagaStep: 'INIT',
        toSagaStep: 'FREEZE_BUYER_PAYMENT',
        operatorType: 'USER',
        operatorId: sellerUserId.toString(),
        remark: '卖方确认转让',
      });

      const outboxEvents = order.getDomainEvents().map((e: DomainEvent) => ({
        eventType: e.type,
        topic: this.getTopicForEvent(e.type),
        key: e.aggregateId,
        payload: e.data,
        aggregateId: e.aggregateId,
        aggregateType: e.aggregateType,
      }));
      uow.addOutboxEvents(outboxEvents);
      await uow.commitOutboxEvents();
    });

    order.clearDomainEvents();
  }

  /**
   * 取消转让
   */
  async cancelTransfer(transferOrderNo: string, userId: bigint): Promise<void> {
    this.logger.log(`Cancelling transfer: ${transferOrderNo}`);

    const order = await this.transferOrderRepo.findByTransferOrderNo(transferOrderNo);
    if (!order) {
      throw new NotFoundException(`转让订单 ${transferOrderNo} 不存在`);
    }

    // 买方或卖方都可取消
    if (order.sellerUserId !== userId && order.buyerUserId !== userId) {
      throw new BadRequestException('仅买方或卖方可以取消');
    }

    order.cancel();

    await this.unitOfWork.executeInTransaction(async (uow) => {
      await uow.saveTransferOrder(order);

      await uow.logStatusChange({
        transferOrderNo: order.transferOrderNo,
        fromStatus: order.status,
        toStatus: TransferOrderStatus.CANCELLED,
        fromSagaStep: order.sagaStep,
        toSagaStep: order.sagaStep,
        operatorType: 'USER',
        operatorId: userId.toString(),
        remark: '用户取消转让',
      });

      const outboxEvents = order.getDomainEvents().map((e: DomainEvent) => ({
        eventType: e.type,
        topic: this.getTopicForEvent(e.type),
        key: e.aggregateId,
        payload: e.data,
        aggregateId: e.aggregateId,
        aggregateType: e.aggregateType,
      }));
      uow.addOutboxEvents(outboxEvents);
      await uow.commitOutboxEvents();
    });

    order.clearDomainEvents();
  }

  /**
   * 查询转让订单详情
   */
  async getTransferOrder(transferOrderNo: string): Promise<TransferOrder | null> {
    return this.transferOrderRepo.findByTransferOrderNo(transferOrderNo);
  }

  /**
   * 查询我的转让记录（作为买方或卖方）
   */
  async getMyTransfers(
    userId: bigint,
    role: 'buyer' | 'seller' | 'all',
    options?: { limit?: number; offset?: number },
  ): Promise<TransferOrder[]> {
    if (role === 'buyer') {
      return this.transferOrderRepo.findByBuyerUserId(userId, options);
    } else if (role === 'seller') {
      return this.transferOrderRepo.findBySellerUserId(userId, options);
    } else {
      const [buyerOrders, sellerOrders] = await Promise.all([
        this.transferOrderRepo.findByBuyerUserId(userId, options),
        this.transferOrderRepo.findBySellerUserId(userId, options),
      ]);
      return [...buyerOrders, ...sellerOrders].sort(
        (a, b) => b.createdAt.getTime() - a.createdAt.getTime(),
      );
    }
  }

  private getTopicForEvent(eventType: string): string {
    const topicMap: Record<string, string> = {
      TransferOrderCreated: 'transfer.order.created',
      TransferStatusChanged: 'transfer.status.changed',
      TransferCompleted: 'transfer.order.completed',
    };
    return topicMap[eventType] || 'transfer.events';
  }
}
