import { Injectable, Inject, Logger } from '@nestjs/common';
import { PlantingOrder } from '../../domain/aggregates/planting-order.aggregate';
import {
  IPlantingOrderRepository,
  PLANTING_ORDER_REPOSITORY,
} from '../../domain/repositories/planting-order.repository.interface';
import {
  IPlantingPositionRepository,
  PLANTING_POSITION_REPOSITORY,
} from '../../domain/repositories/planting-position.repository.interface';
import {
  IPoolInjectionBatchRepository,
  POOL_INJECTION_BATCH_REPOSITORY,
} from '../../domain/repositories/pool-injection-batch.repository.interface';
import { FundAllocationDomainService } from '../../domain/services/fund-allocation.service';
import { WalletServiceClient } from '../../infrastructure/external/wallet-service.client';
import { ReferralServiceClient } from '../../infrastructure/external/referral-service.client';
import { UnitOfWork, UNIT_OF_WORK } from '../../infrastructure/persistence/unit-of-work';
import { OutboxEventData } from '../../infrastructure/persistence/repositories/outbox.repository';
import { PRICE_PER_TREE } from '../../domain/value-objects/fund-allocation-target-type.enum';
import { PaymentCompensationService } from './payment-compensation.service';
import {
  CompensationType,
  FailureStage,
} from '../../infrastructure/persistence/repositories/payment-compensation.repository';
import { TreePricingAdminClient } from '../../infrastructure/external/tree-pricing-admin.client';

export interface CreateOrderResult {
  orderNo: string;
  treeCount: number;
  totalAmount: number;
  status: string;
}

export interface OrderListItem {
  orderNo: string;
  treeCount: number;
  totalAmount: number;
  status: string;
  provinceCode?: string | null;
  cityCode?: string | null;
  isMiningEnabled: boolean;
  createdAt: Date;
}

export interface UserPositionResult {
  totalTreeCount: number;
  effectiveTreeCount: number;
  pendingTreeCount: number;
  distributions: Array<{
    provinceCode: string | null;
    cityCode: string | null;
    treeCount: number;
  }>;
}

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

  constructor(
    @Inject(PLANTING_ORDER_REPOSITORY)
    private readonly orderRepository: IPlantingOrderRepository,
    @Inject(PLANTING_POSITION_REPOSITORY)
    private readonly positionRepository: IPlantingPositionRepository,
    @Inject(POOL_INJECTION_BATCH_REPOSITORY)
    private readonly batchRepository: IPoolInjectionBatchRepository,
    @Inject(UNIT_OF_WORK)
    private readonly unitOfWork: UnitOfWork,
    private readonly fundAllocationService: FundAllocationDomainService,
    private readonly walletService: WalletServiceClient,
    private readonly referralService: ReferralServiceClient,
    private readonly compensationService: PaymentCompensationService,
    private readonly treePricingClient: TreePricingAdminClient,
  ) {}

  /**
   * 创建认种订单
   */
  async createOrder(
    userId: bigint,
    accountSequence: string,
    treeCount: number,
  ): Promise<CreateOrderResult> {
    this.logger.log(`Creating order for user ${accountSequence}, treeCount: ${treeCount}`);

    // 获取当前定价配置（含总部运营成本压力涨价）
    const pricingConfig = await this.treePricingClient.getTreePricingConfig();
    const priceSupplement = pricingConfig.currentSupplement; // 每棵树加价，归总部 (S0000000001)

    // 检查余额 - 使用动态价格（基础价 + 涨价补充）
    const balance = await this.walletService.getBalance(accountSequence);
    const requiredAmount = treeCount * (PRICE_PER_TREE + priceSupplement);
    if (balance.available < requiredAmount) {
      throw new Error(
        `余额不足: 需要 ${requiredAmount} USDT, 当前可用 ${balance.available} USDT`,
      );
    }

    // 创建订单（priceSupplement 快照到订单，确保后续涨价不影响已创建订单）
    const order = PlantingOrder.create(userId, accountSequence, treeCount, priceSupplement);
    await this.orderRepository.save(order);

    this.logger.log(`Order created: ${order.orderNo}`);

    return {
      orderNo: order.orderNo,
      treeCount: order.treeCount.value,
      totalAmount: order.totalAmount,
      status: order.status,
    };
  }

  /**
   * 选择省市
   */
  async selectProvinceCity(
    orderNo: string,
    userId: bigint,
    provinceCode: string,
    provinceName: string,
    cityCode: string,
    cityName: string,
  ): Promise<{ success: boolean; selectedAt: Date }> {
    const order = await this.orderRepository.findByOrderNo(orderNo);
    if (!order) {
      throw new Error('订单不存在');
    }

    if (order.userId !== userId) {
      throw new Error('无权操作此订单');
    }

    order.selectProvinceCity(provinceCode, provinceName, cityCode, cityName);
    await this.orderRepository.save(order);

    return {
      success: true,
      selectedAt: order.provinceCitySelection!.selectedAt,
    };
  }

  /**
   * 确认省市选择 (5秒后调用)
   * 同时在wallet-service中创建对应的省市区域账户
   */
  async confirmProvinceCity(
    orderNo: string,
    userId: bigint,
  ): Promise<{ success: boolean }> {
    const order = await this.orderRepository.findByOrderNo(orderNo);
    if (!order) {
      throw new Error('订单不存在');
    }

    if (order.userId !== userId) {
      throw new Error('无权操作此订单');
    }

    // 获取省市选择信息
    const selection = order.provinceCitySelection;
    if (!selection) {
      throw new Error('请先选择省市');
    }

    // 确认省市选择
    order.confirmProvinceCity();
    await this.orderRepository.save(order);

    // 确保省市区域账户存在（动态创建）
    try {
      const result = await this.walletService.ensureRegionAccounts({
        provinceCode: selection.provinceCode,
        provinceName: selection.provinceName,
        cityCode: selection.cityCode,
        cityName: selection.cityName,
      });
      this.logger.log(
        `区域账户确保完成: 省=${result.provinceAccount.accountSequence}(created=${result.provinceAccount.created}), ` +
        `市=${result.cityAccount.accountSequence}(created=${result.cityAccount.created})`
      );
    } catch (error) {
      // 区域账户创建失败不影响省市确认流程，只记录日志
      this.logger.warn(`创建区域账户失败，将在支付时重试: ${error.message}`);
    }

    return { success: true };
  }

  /**
   * 支付认种订单
   *
   * 采用"预扣款/冻结"模式确保数据一致性:
   * 1. 验证阶段: 获取所有外部依赖数据，检查业务规则
   * 2. 冻结阶段: 先冻结用户资金（可回滚）
   * 3. 执行阶段: 执行数据库事务
   * 4. 确认阶段: 确认扣款或解冻回滚
   */
  async payOrder(
    orderNo: string,
    userId: bigint,
    accountSequence?: string,
  ): Promise<{
    orderNo: string;
    status: string;
    allocations: Array<{
      targetType: string;
      amount: number;
      targetAccountId: string | null;
    }>;
  }> {
    // ==================== 验证阶段 ====================
    // 1. 验证订单状态
    const order = await this.orderRepository.findByOrderNo(orderNo);
    if (!order) {
      throw new Error('订单不存在');
    }

    if (order.userId !== userId) {
      throw new Error('无权操作此订单');
    }

    const selection = order.provinceCitySelection;
    if (!selection) {
      throw new Error('请先选择并确认省市');
    }

    // 2. 验证钱包余额 (先检查，不扣款) - 使用 accountSequence 进行跨服务调用
    const walletIdentifier = accountSequence || order.accountSequence;
    const balance = await this.walletService.getBalance(walletIdentifier);
    if (balance.available < order.totalAmount) {
      throw new Error(
        `余额不足: 需要 ${order.totalAmount} USDT, 当前可用 ${balance.available} USDT`,
      );
    }

    // 注意：资金分配已移至 reward-service，由其调用 authorization-service 进行考核后分配
    // planting-service 只负责：冻结 → 扣款 → 发事件

    // ==================== 冻结阶段 ====================
    // 5. 冻结用户资金（幂等，可回滚）
    let frozen = false;
    try {
      await this.walletService.freezeForPlanting({
        userId: userId.toString(),
        accountSequence: accountSequence,
        amount: order.totalAmount,
        orderId: order.orderNo,
      });
      frozen = true;
      this.logger.log(`Wallet frozen: ${order.totalAmount} USDT for order ${order.orderNo}`);
    } catch (freezeError) {
      this.logger.error(
        `Failed to freeze funds for order ${order.orderNo}: ${freezeError.message}`,
        freezeError.stack,
      );
      throw new Error(`资金冻结失败: ${freezeError.message}`);
    }

    // ==================== 执行阶段 ====================
    try {
      // 6. 标记已支付 (内存操作)
      // 注意：资金分配已移至 reward-service
      // accountSequence 已存储在订单中，用于 wallet-service 结算用户的待领取奖励
      order.markAsPaid();

      // 7. 使用事务保存本地数据库的所有变更 + Outbox事件
      // 这确保了订单状态和事件发布的原子性
      // 注意：用户持仓更新和挖矿开启在合同签署完成后执行
      await this.unitOfWork.executeInTransaction(async (uow) => {
        // 保存订单状态（此时为 PAID 状态，资金冻结中）
        await uow.saveOrder(order);

        // 注意：不在此处更新用户持仓和开启挖矿
        // 持仓更新和挖矿开启在合同签署完成后由 contract.signed 事件触发
        // 这确保了正确的业务流程：支付冻结 -> 签署合同 -> 确认扣款 -> 更新持仓

        // 8. 添加 Outbox 事件（在同一事务中保存）
        // 使用 Outbox Pattern 保证事件发布的可靠性
        const outboxEvents = this.buildOutboxEvents(order, selection, accountSequence);
        uow.addOutboxEvents(outboxEvents);

        // 提交 Outbox 事件（在事务中保存到数据库）
        await uow.commitOutboxEvents();

        this.logger.log(`[OUTBOX] Added ${outboxEvents.length} events to outbox for order ${order.orderNo}`);
      });

      this.logger.log(`Local database transaction committed for order ${order.orderNo}`);

      // 资金保持冻结状态，由 referral-service 在发送 planting.order.paid 前统一确认扣款
      // 这样 planting-service 无需关心 CONTRACT_SIGNING_ENABLED 配置
      this.logger.log(
        `Order ${order.orderNo} paid, funds remain FROZEN. ` +
        `Deduction will be confirmed by referral-service before reward distribution.`,
      );

      this.logger.log(`Order paid successfully: ${order.orderNo}`);

      // 清除已保存到 Outbox 的领域事件
      order.clearDomainEvents();

      return {
        orderNo: order.orderNo,
        status: order.status,
        allocations: [], // 分配由 reward-service 执行
      };
    } catch (error) {
      // 执行阶段出错，需要解冻资金
      this.logger.error(
        `Payment execution error for order ${order.orderNo}: ${error.message}`,
        error.stack,
      );

      if (frozen) {
        // 尝试解冻资金
        try {
          await this.walletService.unfreezeForPlanting({
            userId: userId.toString(),
            accountSequence: accountSequence,
            orderId: order.orderNo,
          });
          this.logger.log(`Wallet unfrozen (rollback) for order ${order.orderNo}`);
        } catch (unfreezeError) {
          // 解冻失败，创建补偿记录以便后台任务处理
          this.logger.error(
            `CRITICAL: Failed to unfreeze funds for order ${order.orderNo}: ${unfreezeError.message}`,
            unfreezeError.stack,
          );

          // 创建补偿记录
          await this.compensationService.createCompensation({
            orderNo: order.orderNo,
            userId,
            amount: order.totalAmount,
            compensationType: CompensationType.UNFREEZE,
            failureReason: error.message,
            failureStage: FailureStage.DB_TRANSACTION,
          });

          this.logger.log(
            `Created UNFREEZE compensation for order ${order.orderNo}, will be processed by background task`,
          );

          throw new Error(
            `支付处理失败，资金将稍后自动解冻，订单 ${order.orderNo}: ${error.message}`,
          );
        }
      }

      throw new Error(`支付处理失败: ${error.message}`);
    }
  }

  /**
   * 查询用户订单列表
   */
  async getUserOrders(
    userId: bigint,
    page: number = 1,
    pageSize: number = 10,
  ): Promise<OrderListItem[]> {
    const orders = await this.orderRepository.findByUserId(
      userId,
      page,
      pageSize,
    );

    return orders.map((o) => ({
      orderNo: o.orderNo,
      treeCount: o.treeCount.value,
      totalAmount: o.totalAmount,
      status: o.status,
      provinceCode: o.provinceCitySelection?.provinceCode,
      cityCode: o.provinceCitySelection?.cityCode,
      isMiningEnabled: o.isMiningEnabled,
      createdAt: o.createdAt,
    }));
  }

  /**
   * 查询用户持仓
   */
  async getUserPosition(userId: bigint): Promise<UserPositionResult> {
    const position = await this.positionRepository.findByUserId(userId);
    if (!position) {
      return {
        totalTreeCount: 0,
        effectiveTreeCount: 0,
        pendingTreeCount: 0,
        distributions: [],
      };
    }

    return {
      totalTreeCount: position.totalTreeCount,
      effectiveTreeCount: position.effectiveTreeCount,
      pendingTreeCount: position.pendingTreeCount,
      distributions: position.distributions.map((d) => ({
        provinceCode: d.provinceCode,
        cityCode: d.cityCode,
        treeCount: d.treeCount,
      })),
    };
  }

  /**
   * 查询订单详情
   */
  async getOrderDetail(
    orderNo: string,
    userId: bigint,
  ): Promise<OrderListItem | null> {
    const order = await this.orderRepository.findByOrderNo(orderNo);
    if (!order || order.userId !== userId) {
      return null;
    }

    return {
      orderNo: order.orderNo,
      treeCount: order.treeCount.value,
      totalAmount: order.totalAmount,
      status: order.status,
      provinceCode: order.provinceCitySelection?.provinceCode,
      cityCode: order.provinceCitySelection?.cityCode,
      isMiningEnabled: order.isMiningEnabled,
      createdAt: order.createdAt,
    };
  }

  /**
   * 取消订单
   */
  async cancelOrder(
    orderNo: string,
    userId: bigint,
  ): Promise<{ success: boolean }> {
    const order = await this.orderRepository.findByOrderNo(orderNo);
    if (!order) {
      throw new Error('订单不存在');
    }

    if (order.userId !== userId) {
      throw new Error('无权操作此订单');
    }

    order.cancel();
    await this.orderRepository.save(order);

    return { success: true };
  }

  /**
   * 构建 Outbox 事件数据
   *
   * 为以下服务创建事件:
   * - referral-service: 更新团队统计 (planting.planting.created)
   *   统计更新后，referral-service 会发送 planting.order.paid 事件给 reward-service
   * - authorization-service: 更新KPI考核 (planting-events)
   *
   * 注意：planting.order.paid 事件已移至 referral-service 发送，
   * 以确保统计数据更新后再计算奖励分配，避免竞态条件。
   */
  private buildOutboxEvents(
    order: PlantingOrder,
    selection: { provinceCode: string; cityCode: string },
    accountSequence?: string,
  ): OutboxEventData[] {
    const events: OutboxEventData[] = [];

    this.logger.debug(`[OUTBOX] Building outbox events for order ${order.orderNo}`);

    // 1. planting.planting.created 事件 (referral-service 消费)
    // referral-service 处理完统计更新后，会发送 planting.order.paid 事件给 reward-service
    events.push({
      eventType: 'planting.planting.created',
      topic: 'planting.planting.created',
      key: accountSequence || order.userId.toString(),
      payload: {
        eventName: 'planting.created',
        data: {
          userId: order.userId.toString(),
          accountSequence: accountSequence || order.userId.toString(), // 添加 accountSequence 用于跨服务关联
          treeCount: order.treeCount.value,
          provinceCode: selection.provinceCode,
          cityCode: selection.cityCode,
          // 新增：订单信息，供 referral-service 转发给 reward-service
          orderId: order.orderNo,
          paidAt: order.paidAt!.toISOString(),
          // [2026-02-26] 总部运营成本压力涨价（每棵树加价金额），归总部 (S0000000001)
          priceSupplement: order.priceSupplement,
          totalAmount: order.totalAmount,
        },
      },
      aggregateId: order.orderNo,
      aggregateType: 'PlantingOrder',
    });

    // 2. planting-events 事件 (authorization-service 消费)
    // 发布所有领域事件
    for (const domainEvent of order.domainEvents) {
      events.push({
        eventType: domainEvent.type,
        topic: 'planting-events',
        key: order.userId.toString(),
        payload: {
          eventName: domainEvent.type,
          aggregateId: domainEvent.aggregateId,
          occurredAt: domainEvent.occurredAt,
          data: domainEvent.data,
        },
        aggregateId: order.orderNo,
        aggregateType: 'PlantingOrder',
      });
    }

    this.logger.debug(`[OUTBOX] Built ${events.length} outbox events for order ${order.orderNo}`);

    return events;
  }

  /**
   * 获取全局认种统计数据
   * 直接从订单表聚合查询，确保数据可靠性
   * [2026-01-06] 更新：添加本月统计
   */
  async getGlobalStats(): Promise<GlobalStatsResult> {
    this.logger.log('Getting global planting stats from database');

    const [globalStats, todayStats, monthStats, statusDistribution] = await Promise.all([
      this.orderRepository.getGlobalStats(),
      this.orderRepository.getTodayStats(),
      this.orderRepository.getMonthStats(),
      this.orderRepository.getStatusDistribution(),
    ]);

    return {
      totalTreeCount: globalStats.totalTreeCount,
      totalOrderCount: globalStats.totalOrderCount,
      totalAmount: globalStats.totalAmount,
      statusDistribution,
      todayStats,
      monthStats,
      calculatedAt: new Date().toISOString(),
    };
  }

  /**
   * 获取认种趋势数据
   * [2026-01-06] 新增
   */
  async getTrendData(period: TrendPeriodType): Promise<TrendDataResult[]> {
    this.logger.log(`Getting planting trend data for period: ${period}`);
    return this.orderRepository.getTrendData(period);
  }
}

/** 全局统计结果 */
export interface GlobalStatsResult {
  /** 总认种棵数（PAID及之后状态） */
  totalTreeCount: number;
  /** 总订单数 */
  totalOrderCount: number;
  /** 总金额 */
  totalAmount: string;
  /** 按状态分布的认种数 */
  statusDistribution: {
    paid: number;
    fundAllocated: number;
    poolScheduled: number;
    poolInjected: number;
    miningEnabled: number;
  };
  /** 今日统计 */
  todayStats: {
    treeCount: number;
    orderCount: number;
    amount: string;
  };
  /** 本月统计 [2026-01-06] 新增 */
  monthStats: {
    treeCount: number;
    orderCount: number;
    amount: string;
  };
  /** 统计时间 */
  calculatedAt: string;
}

/** 趋势时间维度类型 [2026-01-06] 新增 */
export type TrendPeriodType = 'day' | 'week' | 'month' | 'quarter' | 'year';

/** 趋势数据结果 [2026-01-06] 新增 */
export interface TrendDataResult {
  label: string;
  treeCount: number;
  orderCount: number;
  amount: string;
}
