import { Injectable, Inject, Logger } from '@nestjs/common';
import {
  IContractTemplateRepository,
  CONTRACT_TEMPLATE_REPOSITORY,
  IContractSigningTaskRepository,
  CONTRACT_SIGNING_TASK_REPOSITORY,
  IPlantingOrderRepository,
  PLANTING_ORDER_REPOSITORY,
} from '../../domain/repositories';
import {
  ContractTemplate,
  ContractSigningTask,
  SignContractParams,
} from '../../domain/aggregates';
import { ContractSigningStatus } from '../../domain/value-objects';
import { EventPublisherService } from '../../infrastructure/kafka/event-publisher.service';
import { UnitOfWork, UNIT_OF_WORK } from '../../infrastructure/persistence/unit-of-work';
import { IdentityServiceClient } from '../../infrastructure/external/identity-service.client';

/**
 * 创建签署任务的参数
 */
export interface CreateSigningTaskParams {
  orderNo: string;
  userId: bigint;
  accountSequence: string;
  treeCount: number;
  totalAmount: number;
  provinceCode: string;
  provinceName: string;
  cityCode: string;
  cityName: string;
  userPhoneNumber?: string;
  userRealName?: string;
  userIdCardNumber?: string;
}

/**
 * 签署任务DTO
 */
export interface ContractSigningTaskDto {
  contractNo: string;
  orderNo: string;
  contractVersion: string;
  contractContent: string;
  status: string;
  expiresAt: Date;
  treeCount: number;
  totalAmount: number;
  provinceName: string;
  cityName: string;
  userRealName?: string;
  userIdCardNumber?: string;
  userPhoneNumber?: string;
  accountSequence: string;
  scrolledToBottomAt?: Date;
  acknowledgedAt?: Date;
  signedAt?: Date;
  signedPdfUrl?: string;
}

/**
 * 合同签署应用服务
 *
 * 独立模块，不影响现有认种流程
 */
@Injectable()
export class ContractSigningService {
  private readonly logger = new Logger(ContractSigningService.name);

  // 签署有效期（1年）
  private static readonly SIGNING_EXPIRY_HOURS = 24 * 365;

  constructor(
    @Inject(CONTRACT_TEMPLATE_REPOSITORY)
    private readonly templateRepo: IContractTemplateRepository,
    @Inject(CONTRACT_SIGNING_TASK_REPOSITORY)
    private readonly taskRepo: IContractSigningTaskRepository,
    @Inject(PLANTING_ORDER_REPOSITORY)
    private readonly orderRepo: IPlantingOrderRepository,
    @Inject(UNIT_OF_WORK)
    private readonly unitOfWork: UnitOfWork,
    private readonly eventPublisher: EventPublisherService,
    private readonly identityClient: IdentityServiceClient,
  ) {}

  /**
   * 为已支付订单创建合同签署任务
   * 由事件消费者调用
   */
  async createSigningTask(params: CreateSigningTaskParams): Promise<ContractSigningTask> {
    this.logger.log(`Creating contract signing task for order: ${params.orderNo}`);

    // 1. 检查是否已存在签署任务
    const exists = await this.taskRepo.existsByOrderNo(params.orderNo);
    if (exists) {
      this.logger.warn(`Signing task already exists for order: ${params.orderNo}`);
      const existing = await this.taskRepo.findByOrderNo(params.orderNo);
      return existing!;
    }

    // 2. 获取当前有效的合同模板
    const template = await this.templateRepo.findActiveTemplate();
    if (!template) {
      throw new Error('没有可用的合同模板');
    }

    // 3. 生成填充用户信息后的合同内容
    const contractContent = template.generateContractContent({
      userPhoneNumber: params.userPhoneNumber,
      userRealName: params.userRealName,
      userIdCardNumber: params.userIdCardNumber,
      treeCount: params.treeCount,
      totalAmount: params.totalAmount,
      provinceName: params.provinceName,
      cityName: params.cityName,
      orderNo: params.orderNo,
    });

    // 4. 计算过期时间（24小时后）
    const expiresAt = new Date();
    expiresAt.setHours(expiresAt.getHours() + ContractSigningService.SIGNING_EXPIRY_HOURS);

    // 5. 创建签署任务
    const task = ContractSigningTask.create({
      orderNo: params.orderNo,
      userId: params.userId,
      accountSequence: params.accountSequence,
      templateId: template.id!,
      contractVersion: template.version,
      contractContent,
      userPhoneNumber: params.userPhoneNumber,
      userRealName: params.userRealName,
      userIdCardNumber: params.userIdCardNumber,
      treeCount: params.treeCount,
      totalAmount: params.totalAmount,
      provinceCode: params.provinceCode,
      provinceName: params.provinceName,
      cityCode: params.cityCode,
      cityName: params.cityName,
      expiresAt,
    });

    const savedTask = await this.taskRepo.save(task);
    this.logger.log(`Created signing task for order: ${params.orderNo}, expires at: ${expiresAt}`);

    return savedTask;
  }

  /**
   * 获取用户待签署的合同任务
   */
  async getPendingTasks(userId: bigint): Promise<ContractSigningTaskDto[]> {
    const tasks = await this.taskRepo.findPendingByUserId(userId);
    return tasks.map((t) => this.toDto(t));
  }

  /**
   * 获取用户所有未签署的合同任务（包括超时的）
   */
  async getUnsignedTasks(userId: bigint): Promise<ContractSigningTaskDto[]> {
    const tasks = await this.taskRepo.findUnsignedByUserId(userId);
    return tasks.map((t) => this.toDto(t));
  }

  /**
   * 检查用户是否需要先完成 KYC
   *
   * 条件：用户有已付款的认种订单，但没有对应的合同签署任务（因为未完成KYC）
   *
   * @returns 如果需要KYC返回相关信息，否则返回null
   */
  async checkKycRequirement(
    userId: bigint,
    accountSequence: string,
  ): Promise<{ requiresKyc: boolean; paidOrderCount: number; message?: string } | null> {
    try {
      // 1. 查找已付款但没有合同的订单
      const ordersWithoutContract = await this.orderRepo.findPaidOrdersWithoutContract(userId);

      if (ordersWithoutContract.length === 0) {
        return { requiresKyc: false, paidOrderCount: 0 };
      }

      // 2. 检查用户 KYC 状态
      const kycInfo = await this.identityClient.getUserKycInfo(accountSequence);

      if (kycInfo) {
        // 用户已完成 KYC，但合同还没创建（可能是系统延迟）
        // 这种情况不需要强制 KYC，合同会通过 KYC 完成事件自动创建
        this.logger.log(
          `User ${accountSequence} has ${ordersWithoutContract.length} orders without contract, ` +
            `but KYC is complete. Contracts will be created automatically.`,
        );
        return { requiresKyc: false, paidOrderCount: ordersWithoutContract.length };
      }

      // 3. 用户未完成 KYC，需要强制完成
      this.logger.log(
        `User ${accountSequence} has ${ordersWithoutContract.length} paid orders but no KYC. ` +
          `Requiring KYC verification.`,
      );

      return {
        requiresKyc: true,
        paidOrderCount: ordersWithoutContract.length,
        message:
          '系统检测到您已认种了榴莲树，但尚未按国家法规完成实名认证，无法签署合同。请先完成实名认证后才能继续使用APP。',
      };
    } catch (error) {
      this.logger.error(`Failed to check KYC requirement for user ${accountSequence}:`, error);
      // 出错时不阻止用户，返回不需要 KYC
      return { requiresKyc: false, paidOrderCount: 0 };
    }
  }

  /**
   * 获取签署任务详情
   */
  async getTask(orderNo: string, userId: bigint): Promise<ContractSigningTaskDto | null> {
    const task = await this.taskRepo.findByOrderNo(orderNo);
    if (!task) {
      this.logger.warn(`Task not found for orderNo: ${orderNo}`);
      return null;
    }
    // 使用 toString() 比较以避免 BigInt 类型不匹配问题
    if (task.userId.toString() !== userId.toString()) {
      this.logger.warn(`User mismatch for orderNo: ${orderNo}, task.userId=${task.userId}, requestUserId=${userId}`);
      return null;
    }
    return this.toDto(task);
  }

  /**
   * 记录用户已滚动到底部
   */
  async markScrollComplete(orderNo: string, userId: bigint): Promise<void> {
    const task = await this.taskRepo.findByOrderNo(orderNo);
    if (!task || task.userId.toString() !== userId.toString()) {
      throw new Error('签署任务不存在');
    }

    task.markScrolledToBottom();
    await this.taskRepo.save(task);
    this.logger.log(`User ${userId} scrolled to bottom for order: ${orderNo}`);
  }

  /**
   * 记录用户确认法律效力
   */
  async acknowledgeContract(orderNo: string, userId: bigint): Promise<void> {
    const task = await this.taskRepo.findByOrderNo(orderNo);
    if (!task || task.userId.toString() !== userId.toString()) {
      throw new Error('签署任务不存在');
    }

    task.acknowledge();
    await this.taskRepo.save(task);
    this.logger.log(`User ${userId} acknowledged contract for order: ${orderNo}`);
  }

  /**
   * 完成签署
   * 在同一个事务里：更新合同状态 + 更新持仓 + 开启挖矿
   * 事务成功后发布 contract.signed 事件
   */
  async signContract(
    orderNo: string,
    userId: bigint,
    params: SignContractParams,
  ): Promise<void> {
    const task = await this.taskRepo.findByOrderNo(orderNo);
    if (!task || task.userId.toString() !== userId.toString()) {
      throw new Error('签署任务不存在');
    }

    // 幂等性检查：如果已签署，直接返回
    if (task.status === ContractSigningStatus.SIGNED) {
      this.logger.log(`Contract already signed for order: ${orderNo}`);
      return;
    }

    // 获取订单
    const order = await this.orderRepo.findByOrderNo(orderNo);
    if (!order) {
      throw new Error('订单不存在');
    }

    // 幂等性检查：如果订单已开启挖矿，直接返回
    if (order.isMiningEnabled) {
      this.logger.log(`Mining already enabled for order: ${orderNo}`);
      return;
    }

    const selection = order.provinceCitySelection;
    if (!selection) {
      throw new Error('订单缺少省市选择信息');
    }

    // 在同一个事务里完成所有操作
    await this.unitOfWork.executeInTransaction(async (uow) => {
      // 1. 更新合同状态
      task.sign(params);
      await this.taskRepo.save(task);

      // 2. 更新用户持仓
      const position = await uow.getOrCreatePosition(userId);
      position.addPlanting(
        order.treeCount.value,
        selection.provinceCode,
        selection.cityCode,
      );
      await uow.savePosition(position);

      // 3. 开启挖矿
      order.enableMining();
      await uow.saveOrder(order);
    });

    this.logger.log(`User ${userId} signed contract for order: ${orderNo}, position updated, mining enabled`);

    // 事务成功后发布事件（给 reward-service）
    await this.eventPublisher.publishContractSigned({
      orderNo: task.orderNo,
      userId: task.userId.toString(),
      accountSequence: task.accountSequence,
      treeCount: task.treeCount,
      totalAmount: task.totalAmount,
      provinceCode: task.provinceCode,
      cityCode: task.cityCode,
      signedAt: task.signedAt?.toISOString(),
      priceSupplement: order.priceSupplement,
    });
  }

  /**
   * 补签合同（超时后用户仍可补签）
   */
  async lateSignContract(
    orderNo: string,
    userId: bigint,
    params: SignContractParams,
  ): Promise<void> {
    const task = await this.taskRepo.findByOrderNo(orderNo);
    if (!task || task.userId.toString() !== userId.toString()) {
      throw new Error('签署任务不存在');
    }

    task.lateSign(params);
    await this.taskRepo.save(task);
    this.logger.log(`User ${userId} late-signed contract for order: ${orderNo}`);
  }

  /**
   * 处理过期未签署的任务
   * 由定时任务调用
   * 在同一个事务里：更新合同状态 + 更新持仓 + 开启挖矿
   * 事务成功后发布 contract.expired 事件，触发 reward-service 执行系统账户分配
   */
  async handleExpiredTasks(): Promise<number> {
    const expiredTasks = await this.taskRepo.findExpiredPendingTasks();
    let count = 0;

    for (const task of expiredTasks) {
      try {
        // 获取订单
        const order = await this.orderRepo.findByOrderNo(task.orderNo);
        if (!order) {
          this.logger.error(`Order not found for expired task: ${task.orderNo}`);
          continue;
        }

        // 幂等性检查
        if (order.isMiningEnabled) {
          this.logger.log(`Mining already enabled for expired order: ${task.orderNo}`);
          continue;
        }

        const selection = order.provinceCitySelection;
        if (!selection) {
          this.logger.error(`Order ${task.orderNo} has no province/city selection`);
          continue;
        }

        // 在同一个事务里完成所有操作
        await this.unitOfWork.executeInTransaction(async (uow) => {
          // 1. 更新合同状态为超时
          task.markAsTimeout();
          await this.taskRepo.save(task);

          // 2. 更新用户持仓（树还是种了，权益归总部）
          const position = await uow.getOrCreatePosition(task.userId);
          position.addPlanting(
            order.treeCount.value,
            selection.provinceCode,
            selection.cityCode,
          );
          await uow.savePosition(position);

          // 3. 开启挖矿
          order.enableMining();
          await uow.saveOrder(order);
        });

        // 事务成功后发布合同超时事件，触发系统账户奖励分配
        await this.eventPublisher.publishContractExpired({
          orderNo: task.orderNo,
          userId: task.userId.toString(),
          accountSequence: task.accountSequence,
          treeCount: task.treeCount,
          totalAmount: task.totalAmount,
          provinceCode: task.provinceCode,
          cityCode: task.cityCode,
          expiredAt: new Date().toISOString(),
          priceSupplement: order.priceSupplement,
        });

        count++;
        this.logger.log(`Expired task processed: orderNo=${task.orderNo}, position updated, mining enabled`);
      } catch (error) {
        this.logger.error(`Failed to handle expired task: orderNo=${task.orderNo}`, error);
      }
    }

    if (count > 0) {
      this.logger.log(`Processed ${count} expired signing tasks`);
    }

    return count;
  }

  /**
   * 获取当前有效的合同模板
   */
  async getActiveTemplate(): Promise<ContractTemplate | null> {
    return this.templateRepo.findActiveTemplate();
  }

  /**
   * 创建合同模板（管理后台使用）
   */
  async createTemplate(params: {
    version: string;
    title: string;
    content: string;
    effectiveFrom: Date;
    effectiveTo?: Date;
  }): Promise<ContractTemplate> {
    const template = ContractTemplate.create(params);
    return this.templateRepo.save(template);
  }

  private toDto(task: ContractSigningTask): ContractSigningTaskDto {
    return {
      orderNo: task.orderNo,
      contractNo: task.contractNo,
      contractVersion: task.contractVersion,
      contractContent: task.contractContent,
      status: task.status,
      expiresAt: task.expiresAt,
      treeCount: task.treeCount,
      totalAmount: task.totalAmount,
      provinceName: task.provinceName,
      cityName: task.cityName,
      userRealName: task.userRealName,
      userIdCardNumber: task.userIdCardNumber,
      userPhoneNumber: task.userPhoneNumber,
      accountSequence: task.accountSequence,
      scrolledToBottomAt: task.scrolledToBottomAt,
      acknowledgedAt: task.acknowledgedAt,
      signedAt: task.signedAt,
      signedPdfUrl: task.signedPdfUrl,
    };
  }
}
