import { Injectable, Logger } from '@nestjs/common';
import { OrderRepository } from '../../infrastructure/persistence/repositories/order.repository';
import { TradingAccountRepository } from '../../infrastructure/persistence/repositories/trading-account.repository';
import { CirculationPoolRepository } from '../../infrastructure/persistence/repositories/circulation-pool.repository';
import { SharePoolRepository } from '../../infrastructure/persistence/repositories/share-pool.repository';
import { OutboxRepository } from '../../infrastructure/persistence/repositories/outbox.repository';
import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service';
import { RedisService } from '../../infrastructure/redis/redis.service';
import { OrderAggregate, OrderType, OrderStatus, OrderSource } from '../../domain/aggregates/order.aggregate';
import { TradingAccountAggregate } from '../../domain/aggregates/trading-account.aggregate';
import { MatchingEngineService } from '../../domain/services/matching-engine.service';
import { Money } from '../../domain/value-objects/money.vo';
import { BurnService } from './burn.service';
import { PriceService } from './price.service';
import {
  TradingEventTypes,
  TradingTopics,
  OrderCreatedPayload,
  OrderCancelledPayload,
  TradeExecutedPayload,
} from '../../domain/events/trading.events';

// 交易手续费率：10%
const TRADE_FEE_RATE = 0.1;

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

  constructor(
    private readonly orderRepository: OrderRepository,
    private readonly accountRepository: TradingAccountRepository,
    private readonly circulationPoolRepository: CirculationPoolRepository,
    private readonly sharePoolRepository: SharePoolRepository,
    private readonly outboxRepository: OutboxRepository,
    private readonly prisma: PrismaService,
    private readonly redis: RedisService,
    private readonly burnService: BurnService,
    private readonly priceService: PriceService,
  ) {}

  async createOrder(
    accountSequence: string,
    type: OrderType,
    price: string,
    quantity: string,
    source: OrderSource = OrderSource.USER,
    sourceLabel?: string,
  ): Promise<{ orderId: string; orderNo: string; status: OrderStatus; filledQuantity: string }> {
    const lockValue = await this.redis.acquireLock(`order:create:${accountSequence}`, 10);
    if (!lockValue) {
      throw new Error('System busy, please try again');
    }

    try {
      // 验证账户
      let account = await this.accountRepository.findByAccountSequence(accountSequence);
      if (!account) {
        account = TradingAccountAggregate.create(accountSequence);
      }

      const priceAmount = new Money(price);
      const quantityAmount = new Money(quantity);
      const totalCost = quantityAmount.multiply(priceAmount.value);

      // 检查余额并冻结
      if (type === OrderType.BUY) {
        if (account.availableCash.isLessThan(totalCost)) {
          throw new Error('Insufficient cash balance');
        }
      } else {
        if (account.availableShares.isLessThan(quantityAmount)) {
          throw new Error('Insufficient share balance');
        }
      }

      // 生成订单号
      const orderNo = this.generateOrderNo();

      // 创建订单
      const order = OrderAggregate.create(orderNo, accountSequence, type, priceAmount, quantityAmount, source, sourceLabel);

      // 冻结资产
      if (type === OrderType.BUY) {
        account.freezeCash(totalCost, orderNo);
      } else {
        account.freezeShares(quantityAmount, orderNo);
      }

      // 保存订单和账户
      const orderId = await this.orderRepository.save(order);
      await this.accountRepository.save(account);

      // 发布订单创建事件
      await this.publishOrderCreatedEvent(orderId, order);

      // 重新从数据库获取订单（确保有id）
      const savedOrder = await this.orderRepository.findByOrderNo(orderNo);
      if (!savedOrder) {
        throw new Error('Failed to retrieve saved order');
      }

      // 尝试撮合
      await this.tryMatch(savedOrder);

      // 获取最新订单状态
      const updatedOrder = await this.orderRepository.findByOrderNo(orderNo);

      return {
        orderId,
        orderNo,
        status: updatedOrder?.status || order.status,
        filledQuantity: updatedOrder?.filledQuantity.toString() || '0',
      };
    } finally {
      await this.redis.releaseLock(`order:create:${accountSequence}`, lockValue);
    }
  }

  async cancelOrder(accountSequence: string, orderNo: string): Promise<void> {
    const order = await this.orderRepository.findByOrderNo(orderNo);
    if (!order) {
      throw new Error('Order not found');
    }
    if (order.accountSequence !== accountSequence) {
      throw new Error('Unauthorized');
    }

    const account = await this.accountRepository.findByAccountSequence(accountSequence);
    if (!account) {
      throw new Error('Account not found');
    }

    // 取消订单
    order.cancel();

    // 解冻资产
    if (order.type === OrderType.BUY) {
      account.unfreezeCash(order.lockedAmount, orderNo);
    } else {
      account.unfreezeShares(order.remainingQuantity, orderNo);
    }

    await this.orderRepository.save(order);
    await this.accountRepository.save(account);

    // 发布订单取消事件
    await this.publishOrderCancelledEvent(order);
  }

  private async tryMatch(incomingOrder: OrderAggregate): Promise<void> {
    const lockValue = await this.redis.acquireLock('order:matching', 30);
    if (!lockValue) return;

    try {
      const oppositeType = incomingOrder.type === OrderType.BUY ? OrderType.SELL : OrderType.BUY;
      const orderBook = await this.orderRepository.findActiveOrders(oppositeType);

      const matches = this.matchingEngine.findMatchingOrders(incomingOrder, orderBook);

      for (const match of matches) {
        const tradeQuantity = match.trade.quantity;
        let burnQuantity = Money.zero();
        let effectiveQuantity = tradeQuantity;

        // 如果是卖出成交，执行销毁逻辑
        // 卖出的销毁量 = 卖出积分股 × 倍数
        // 卖出交易额 = (卖出量 + 卖出销毁量) × 积分股价
        if (match.sellOrder) {
          try {
            const burnResult = await this.burnService.executeSellBurn(
              tradeQuantity,
              match.sellOrder.accountSequence,
              match.sellOrder.orderNo,
            );
            burnQuantity = burnResult.burnQuantity;
            effectiveQuantity = new Money(tradeQuantity.value.plus(burnQuantity.value));

            this.logger.log(
              `Sell burn executed: sellQty=${tradeQuantity.toFixed(8)}, ` +
                `burnQty=${burnQuantity.toFixed(8)}, effectiveQty=${effectiveQuantity.toFixed(8)}`,
            );
          } catch (error) {
            this.logger.warn(`Sell burn failed, continuing without burn: ${error}`);
          }
        }

        // 计算交易额
        // 买方支付：原始数量 × 价格（买方冻结的是这个金额）
        const buyerPayAmount = new Money(tradeQuantity.value.times(match.trade.price.value));
        // 卖方总收益（含销毁倍数）：有效数量 × 价格
        const sellerGrossAmount = new Money(effectiveQuantity.value.times(match.trade.price.value));
        // 交易手续费（10%）：从卖方收益中扣除
        const tradeFee = new Money(sellerGrossAmount.value.times(TRADE_FEE_RATE));
        // 卖方实际收到：总收益 - 手续费
        const sellerReceiveAmount = new Money(sellerGrossAmount.value.minus(tradeFee.value));

        // 保存成交记录（包含销毁信息、手续费和来源标识）
        await this.prisma.trade.create({
          data: {
            tradeNo: match.trade.tradeNo,
            buyOrderId: match.buyOrder.id!,
            sellOrderId: match.sellOrder.id!,
            buyerSequence: match.buyOrder.accountSequence,
            sellerSequence: match.sellOrder.accountSequence,
            price: match.trade.price.value,
            quantity: tradeQuantity.value,
            burnQuantity: burnQuantity.value,
            effectiveQty: effectiveQuantity.value,
            amount: sellerReceiveAmount.value,
            fee: tradeFee.value,
            buyerSource: match.buyOrder.source,
            sellerSource: match.sellOrder.source,
          },
        });

        // 卖出的积分股进入流通池
        try {
          await this.circulationPoolRepository.addSharesFromSell(
            tradeQuantity,
            match.sellOrder.accountSequence,
            match.sellOrder.id!,
            `卖出成交, 交易号${match.trade.tradeNo}`,
          );
        } catch (error) {
          this.logger.warn(`Failed to add shares to circulation pool: ${error}`);
        }

        // 10%手续费进入积分股池（greenPoints）
        try {
          await this.sharePoolRepository.feeIn(
            tradeFee,
            match.trade.tradeNo,
            match.buyOrder.accountSequence,
            match.sellOrder.accountSequence,
            match.buyOrder.source,
            match.sellOrder.source,
          );
          this.logger.debug(
            `Trade fee added to share pool: ${tradeFee.toFixed(8)}, tradeNo=${match.trade.tradeNo}`,
          );
        } catch (error) {
          this.logger.error(`Failed to add trade fee to share pool: ${error}`);
        }

        // 更新订单（包含销毁信息）
        await this.orderRepository.save(match.buyOrder);
        await this.orderRepository.saveWithBurnInfo(match.sellOrder, burnQuantity, effectiveQuantity);

        // 更新买方账户（支付原始交易额）
        const buyerAccount = await this.accountRepository.findByAccountSequence(match.buyOrder.accountSequence);
        if (buyerAccount) {
          buyerAccount.executeBuy(tradeQuantity, buyerPayAmount, match.trade.tradeNo);
          await this.accountRepository.save(buyerAccount);
        }

        // 更新卖方账户（收到扣除手续费后的金额）
        const sellerAccount = await this.accountRepository.findByAccountSequence(match.sellOrder.accountSequence);
        if (sellerAccount) {
          sellerAccount.executeSell(tradeQuantity, sellerReceiveAmount, match.trade.tradeNo);
          await this.accountRepository.save(sellerAccount);
        }

        this.logger.log(
          `Trade executed: ${match.trade.tradeNo}, price=${match.trade.price.toFixed(8)}, ` +
            `qty=${tradeQuantity.toFixed(8)}, burn=${burnQuantity.toFixed(8)}, ` +
            `buyerPay=${buyerPayAmount.toFixed(8)}, fee=${tradeFee.toFixed(8)}, sellerReceive=${sellerReceiveAmount.toFixed(8)}`,
        );

        // 发布成交事件
        await this.publishTradeExecutedEvent(
          match.trade.tradeNo,
          match.buyOrder,
          match.sellOrder,
          match.trade.price,
          tradeQuantity,
          sellerReceiveAmount,
          burnQuantity,
          effectiveQuantity,
        );
      }
    } finally {
      await this.redis.releaseLock('order:matching', lockValue);
    }
  }

  private generateOrderNo(): string {
    const timestamp = Date.now().toString(36);
    const random = Math.random().toString(36).substring(2, 8);
    return `O${timestamp}${random}`.toUpperCase();
  }

  // ==================== 事件发布方法 ====================

  /**
   * 发布订单创建事件
   */
  private async publishOrderCreatedEvent(orderId: string, order: OrderAggregate): Promise<void> {
    try {
      const payload: OrderCreatedPayload = {
        orderId,
        orderNo: order.orderNo,
        accountSequence: order.accountSequence,
        type: order.type,
        price: order.price.toString(),
        quantity: order.quantity.toString(),
        createdAt: new Date().toISOString(),
      };

      await this.outboxRepository.create({
        aggregateType: 'Order',
        aggregateId: orderId,
        eventType: TradingEventTypes.ORDER_CREATED,
        payload,
        topic: TradingTopics.ORDERS,
        key: order.accountSequence,
      });

      this.logger.debug(`Published OrderCreated event for order ${order.orderNo}`);
    } catch (error) {
      this.logger.error(`Failed to publish OrderCreated event: ${error}`);
    }
  }

  /**
   * 发布订单取消事件
   */
  private async publishOrderCancelledEvent(order: OrderAggregate): Promise<void> {
    try {
      const payload: OrderCancelledPayload = {
        orderId: order.id!,
        orderNo: order.orderNo,
        accountSequence: order.accountSequence,
        type: order.type,
        cancelledQuantity: order.remainingQuantity.toString(),
        cancelledAt: new Date().toISOString(),
      };

      await this.outboxRepository.create({
        aggregateType: 'Order',
        aggregateId: order.id!,
        eventType: TradingEventTypes.ORDER_CANCELLED,
        payload,
        topic: TradingTopics.ORDERS,
        key: order.accountSequence,
      });

      this.logger.debug(`Published OrderCancelled event for order ${order.orderNo}`);
    } catch (error) {
      this.logger.error(`Failed to publish OrderCancelled event: ${error}`);
    }
  }

  /**
   * 发布成交事件
   */
  private async publishTradeExecutedEvent(
    tradeNo: string,
    buyOrder: OrderAggregate,
    sellOrder: OrderAggregate,
    price: Money,
    quantity: Money,
    amount: Money,
    burnQuantity: Money,
    effectiveQuantity: Money,
  ): Promise<void> {
    try {
      // 使用 tradeNo 查找刚创建的 trade 获取 id
      const trade = await this.prisma.trade.findUnique({ where: { tradeNo } });
      if (!trade) {
        this.logger.warn(`Trade not found for event publishing: ${tradeNo}`);
        return;
      }

      const payload: TradeExecutedPayload = {
        tradeId: trade.id,
        tradeNo,
        buyOrderId: buyOrder.id!,
        sellOrderId: sellOrder.id!,
        buyerSequence: buyOrder.accountSequence,
        sellerSequence: sellOrder.accountSequence,
        price: price.toString(),
        quantity: quantity.toString(),
        amount: amount.toString(),
        burnQuantity: burnQuantity.toString(),
        effectiveQuantity: effectiveQuantity.toString(),
        createdAt: new Date().toISOString(),
      };

      await this.outboxRepository.create({
        aggregateType: 'Trade',
        aggregateId: trade.id,
        eventType: TradingEventTypes.TRADE_EXECUTED,
        payload,
        topic: TradingTopics.TRADES,
        key: tradeNo,
      });

      this.logger.debug(`Published TradeExecuted event for trade ${tradeNo}`);
    } catch (error) {
      this.logger.error(`Failed to publish TradeExecuted event: ${error}`);
    }
  }
}
