import { GenericCrudService } from '@d8d/shared-crud';
import { DataSource, Repository, LessThanOrEqual } from 'typeorm';
import { FeiePrintTaskMt } from '../entities/feie-print-task.mt.entity';
import { FeiePrinterMt } from '../entities/feie-printer.mt.entity';
import { FeieConfigMt } from '../entities/feie-config.mt.entity';
import { FeieApiService } from './feie-api.service';
import { PrinterService } from './printer.service';
import { FeieApiConfig, CreatePrintTaskDto, PrintStatus, PrintType, CancelReason } from '../types/feie.types';
import { createServiceLogger } from '@d8d/shared-utils';

export class PrintTaskService extends GenericCrudService<FeiePrintTaskMt> {
  private feieApiService: FeieApiService;
  private printerService: PrinterService;
  private printerRepository: Repository<FeiePrinterMt>;
  private configRepository: Repository<FeieConfigMt>;
  private defaultRetryInterval: number = 5000; // 默认5秒重试间隔
  private defaultMaxRetries: number = 3; // 默认最大重试次数
  private logger: ReturnType<typeof createServiceLogger>;

  constructor(dataSource: DataSource, feieConfig: FeieApiConfig) {
    super(dataSource, FeiePrintTaskMt, {
      tenantOptions: { enabled: true, tenantIdField: 'tenantId' }
    });

    this.feieApiService = new FeieApiService(feieConfig);
    this.printerService = new PrinterService(dataSource, feieConfig);
    this.printerRepository = dataSource.getRepository(FeiePrinterMt);
    this.configRepository = dataSource.getRepository(FeieConfigMt);
    this.logger = createServiceLogger('feie-print-task-service');
  }

  /**
   * 创建打印任务
   */
  async createPrintTask(tenantId: number, taskDto: CreatePrintTaskDto): Promise<FeiePrintTaskMt> {
    // 验证打印机是否存在且可用
    const printer = await this.printerRepository.findOne({
      where: {
        tenantId,
        printerSn: taskDto.printerSn
      }
    });

    if (!printer) {
      throw new Error('打印机不存在');
    }

    // 生成任务ID
    const taskId = this.generateTaskId();

    // 计算计划打印时间
    let scheduledAt: Date | null = null;
    let printStatus = PrintStatus.DELAYED; // 所有通过此方法创建的任务都标记为DELAYED状态

    // 如果delaySeconds未定义或小于0，视为0
    const delaySeconds = taskDto.delaySeconds || 0;

    // 使用数据库时间计算计划时间，避免时间差异问题
    try {
      // 获取当前数据库时间
      const dbTimeResult = await this.dataSource.query('SELECT NOW() as db_time');
      const dbNow = new Date(dbTimeResult[0].db_time);

      if (delaySeconds >= 0) {
        scheduledAt = new Date(dbNow.getTime() + delaySeconds * 1000);
      } else {
        // 如果delaySeconds为负数，立即执行
        scheduledAt = dbNow;
      }
    } catch (error) {
      const message = `获取数据库时间失败，使用本地时间: ${error}`;
      console.warn(message);
      await this.logger.warn(message);
      // 回退到本地时间
      if (delaySeconds >= 0) {
        scheduledAt = new Date(Date.now() + delaySeconds * 1000);
      } else {
        scheduledAt = new Date();
      }
    }

    // 确保scheduledAt不为null
    if (!scheduledAt) {
      scheduledAt = new Date();
    }

    // 获取配置的最大重试次数
    const maxRetries = await this.getMaxRetries(tenantId);

    // 创建打印任务记录
    const printTask = await this.create({
      tenantId,
      taskId,
      orderId: taskDto.orderId || null,
      printerSn: taskDto.printerSn,
      content: taskDto.content,
      printType: taskDto.printType,
      printStatus,
      scheduledAt,
      retryCount: 0,
      maxRetries
    });

    // 如果是立即打印（delaySeconds <= 0），则立即执行
    if (delaySeconds <= 0) {
      await this.executePrintTask(tenantId, taskId);
    }

    return printTask;
  }

  /**
   * 获取租户配置值
   */
  private async getTenantConfigValue(tenantId: number, key: string, defaultValue: string): Promise<string> {
    try {
      const config = await this.configRepository.findOne({
        where: { tenantId, configKey: key }
      });
      return config?.configValue || defaultValue;
    } catch (error) {
      const message = `[租户${tenantId}] 获取配置失败，key: ${key}: ${error}`;
      console.warn(message);
      await this.logger.warn(message);
      return defaultValue;
    }
  }

  /**
   * 获取重试间隔（毫秒）
   */
  private async getRetryInterval(tenantId: number): Promise<number> {
    // 使用固定值5000毫秒（5秒）
    return 5000;
  }

  /**
   * 获取最大重试次数
   */
  private async getMaxRetries(tenantId: number): Promise<number> {
    // 使用固定值1次
    return 1;
  }

  /**
   * 执行打印任务
   */
  async executePrintTask(tenantId: number, taskId: string): Promise<FeiePrintTaskMt> {
    // 使用数据库事务和乐观锁来防止重复执行
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    await this.logger.info("tenantId", { tenantId });
    await this.logger.info("taskId", { taskId });

    try {
      // 在事务中获取任务，使用SELECT FOR UPDATE锁定行
      const task = await queryRunner.manager.findOne(FeiePrintTaskMt, {
        where: { tenantId, taskId } as any,
        lock: { mode: 'pessimistic_write' }
      });

      await this.logger.info("task", { task });

      if (!task) {
        await queryRunner.rollbackTransaction();
        throw new Error('打印任务不存在');
      }

      // 检查任务状态 - 如果已经是最终状态，直接返回
      if ([PrintStatus.CANCELLED, PrintStatus.SUCCESS].includes(task.printStatus as PrintStatus)) {
        await queryRunner.rollbackTransaction();
        const errorMsg = task.printStatus === PrintStatus.CANCELLED ? '打印任务已取消' : '打印任务已完成';
        throw new Error(errorMsg);
      }

      // 检查任务是否已经在打印中（防止重复执行）
      if (task.printStatus === PrintStatus.PRINTING) {
        await queryRunner.rollbackTransaction();
        const message = `[租户${tenantId}] 打印任务 ${taskId} 已经在打印中，跳过重复执行`;
        console.warn(message);
        await this.logger.warn(message);
        return task;
      }

      // 更新状态为打印中
      task.printStatus = PrintStatus.PRINTING;
      task.errorMessage = null;
      await queryRunner.manager.save(task);

      // 提交事务，释放锁
      await queryRunner.commitTransaction();

      try {
        // 调用飞鹅API打印
        const response = await this.feieApiService.printReceipt({
          sn: task.printerSn,
          content: task.content,
          times: 1
        });

        console.debug("调用飞鹅API打印response：",response);
        await this.logger.debug("调用飞鹅API打印response", { response });

        // 更新任务状态为成功
        const updatedTask = await this.update(task.id, {
          printStatus: PrintStatus.SUCCESS,
          printedAt: new Date(),
          errorMessage: null
        });

        console.debug("更新任务状态为成功updatedTask：",updatedTask);
        await this.logger.debug("更新任务状态为成功updatedTask：", { updatedTask });

        if (!updatedTask) {
          throw new Error('更新打印任务状态失败');
        }

        return updatedTask;
      } catch (error) {
        await this.logger.info("executePrintTask执行失败：", { error });
        // 处理打印失败
        const errorMessage = error instanceof Error ? error.message : '打印失败';

        // 检查是否是订单重复错误（飞鹅API错误代码 -6）
        // 如果订单号重复，说明飞鹅那边已经打印成功，只是本地不知道
        if (errorMessage.includes('错误代码: -6') || errorMessage.includes('订单号重复')) {
          const message = `[租户${tenantId}] 打印任务 ${taskId} 订单号重复，飞鹅API已打印，标记为成功`;
          console.log(message);
          await this.logger.info(message);

          // 更新任务状态为成功（因为飞鹅那边已经打印了）
          const updatedTask = await this.update(task.id, {
            printStatus: PrintStatus.SUCCESS,
            printedAt: new Date(),
            errorMessage: '订单号重复，飞鹅API已打印',
            retryCount: task.retryCount + 1
          });

          if (!updatedTask) {
            throw new Error('更新打印任务状态失败');
          }

          return updatedTask;
        }

        // 获取配置的最大重试次数
        const maxRetries = await this.getMaxRetries(tenantId);
        await this.logger.info("maxRetries最大重试次数：", { maxRetries });

        // 检查是否需要重试
        const shouldRetry = task.retryCount < maxRetries;

        const updateData: Partial<FeiePrintTaskMt> = {
          errorMessage,
          retryCount: task.retryCount + 1,
          maxRetries // 更新最大重试次数配置
        };
        await this.logger.info("updateData：", { updateData });

        if (shouldRetry) {
          updateData.printStatus = PrintStatus.PENDING;
        } else {
          updateData.printStatus = PrintStatus.FAILED;
        }

        const updatedTask = await this.update(task.id, updateData);
        await this.logger.info("updatedTask：", { updatedTask });

        if (shouldRetry) {
          // 获取配置的重试间隔
          const retryInterval = await this.getRetryInterval(tenantId);
          await this.logger.info("retryInterval：", { retryInterval });

          const message = `[租户${tenantId}] 打印任务 ${taskId} 失败，${retryInterval}ms后重试，当前重试次数: ${task.retryCount + 1}/${maxRetries}`;
          console.log(message);
          await this.logger.info(message);

          // 安排重试
          setTimeout(() => {
            this.executePrintTask(tenantId, taskId).catch(async (error) => {
              console.error('重试打印任务失败:', error);
              await this.logger.error('重试打印任务失败', { error: error.message, taskId, tenantId });
            });
          }, retryInterval);
        } else {
          const message = `[租户${tenantId}] 打印任务 ${taskId} 失败，已达到最大重试次数 ${maxRetries}，任务标记为失败`;
          console.log(message);
          await this.logger.info("打印任务:",message);
        }

        throw error;
      }
    } catch (error) {
      // 只有在事务未提交或未回滚时才回滚
      try {
        await queryRunner.rollbackTransaction();
      } catch (rollbackError) {
        // 如果事务已经结束，忽略回滚错误
        if (!(rollbackError instanceof Error && rollbackError.message.includes('Transaction is not started yet'))) {
          const message = `[租户${tenantId}] 回滚事务失败: ${rollbackError}`;
          console.warn(message);
          await this.logger.warn(message);
        }
      }
      throw error;
    } finally {
      // 释放queryRunner
      await queryRunner.release();
    }
  }

  /**
   * 取消打印任务
   */
  async cancelPrintTask(
    tenantId: number,
    taskId: string,
    reason: CancelReason = CancelReason.MANUAL
  ): Promise<FeiePrintTaskMt> {
    const task = await this.repository.findOne({
      where: { tenantId, taskId } as any
    });

    if (!task) {
      throw new Error('打印任务不存在');
    }

    // 检查任务状态是否可以取消
    if ([PrintStatus.SUCCESS, PrintStatus.CANCELLED].includes(task.printStatus as PrintStatus)) {
      throw new Error(`打印任务状态为${task.printStatus}，无法取消`);
    }

    // 更新任务状态
    const updatedTask = await this.update(task.id, {
      printStatus: PrintStatus.CANCELLED,
      cancelledAt: new Date(),
      cancelReason: reason
    });

    if (!updatedTask) {
      throw new Error('更新打印任务状态失败');
    }

    return updatedTask;
  }

  /**
   * 重试打印任务
   */
  async retryPrintTask(tenantId: number, taskId: string): Promise<FeiePrintTaskMt> {
    const task = await this.repository.findOne({
      where: { tenantId, taskId } as any
    });

    if (!task) {
      throw new Error('打印任务不存在');
    }

    // 检查任务状态是否可以重试
    if (task.printStatus !== PrintStatus.FAILED) {
      throw new Error('只有失败的打印任务可以重试');
    }

    // 重置重试计数和错误信息
    const updatedTask = await this.update(task.id, {
      printStatus: PrintStatus.PENDING,
      errorMessage: null,
      retryCount: 0
    });

    if (!updatedTask) {
      throw new Error('更新打印任务状态失败');
    }

    // 立即执行重试
    await this.executePrintTask(tenantId, taskId);

    return updatedTask;
  }

  /**
   * 查询打印任务状态
   */
  async getPrintTaskStatus(tenantId: number, taskId: string): Promise<any> {
    const task = await this.repository.findOne({
      where: { tenantId, taskId } as any
    });

    if (!task) {
      throw new Error('打印任务不存在');
    }

    // 如果任务已完成，返回本地状态
    if (task.printStatus === PrintStatus.SUCCESS || task.printStatus === PrintStatus.CANCELLED) {
      return {
        taskId: task.taskId,
        printStatus: task.printStatus,
        printedAt: task.printedAt,
        cancelledAt: task.cancelledAt,
        cancelReason: task.cancelReason,
        errorMessage: task.errorMessage
      };
    }

    // 查询飞鹅API获取最新状态
    try {
      const response = await this.feieApiService.queryOrderStatus(taskId);

      // 根据飞鹅API响应更新本地状态
      let newStatus = task.printStatus;
      if (response.data === '已打印') {
        newStatus = PrintStatus.SUCCESS;
      } else if (response.data === '打印失败') {
        newStatus = PrintStatus.FAILED;
      }

      if (newStatus !== task.printStatus) {
        const updateData: Partial<FeiePrintTaskMt> = {
          printStatus: newStatus
        };

        if (newStatus === PrintStatus.SUCCESS) {
          updateData.printedAt = new Date();
        }

        await this.update(task.id, updateData);
      }

      return {
        taskId: task.taskId,
        printStatus: newStatus,
        remoteStatus: response.data,
        printedAt: task.printedAt,
        errorMessage: task.errorMessage
      };
    } catch (error) {
      // API查询失败，返回本地状态
      return {
        taskId: task.taskId,
        printStatus: task.printStatus,
        printedAt: task.printedAt,
        errorMessage: task.errorMessage,
        apiError: error instanceof Error ? error.message : '查询API失败'
      };
    }
  }

  /**
   * 获取打印任务列表
   */
  async getPrintTasks(
    tenantId: number,
    filters: {
      orderId?: number;
      printerSn?: string;
      printType?: PrintType;
      printStatus?: PrintStatus;
      startDate?: Date;
      endDate?: Date;
      search?: string;
    } = {},
    page: number = 1,
    limit: number = 20
  ): Promise<{ tasks: FeiePrintTaskMt[]; total: number }> {
    const where: any = { tenantId };

    if (filters.orderId) {
      where.orderId = filters.orderId;
    }

    if (filters.printerSn) {
      where.printerSn = filters.printerSn;
    }

    if (filters.printType) {
      where.printType = filters.printType;
    }

    if (filters.printStatus) {
      where.printStatus = filters.printStatus;
    }

    if (filters.startDate || filters.endDate) {
      where.createdAt = {};
      if (filters.startDate) {
        where.createdAt.$gte = filters.startDate;
      }
      if (filters.endDate) {
        where.createdAt.$lte = filters.endDate;
      }
    }

    // 构建查询
    const queryBuilder = this.repository.createQueryBuilder('task')
      .where('task.tenantId = :tenantId', { tenantId })
      .orderBy('task.createdAt', 'DESC');

    // 应用筛选条件
    if (filters.orderId) {
      queryBuilder.andWhere('task.orderId = :orderId', { orderId: filters.orderId });
    }

    if (filters.printerSn) {
      queryBuilder.andWhere('task.printerSn = :printerSn', { printerSn: filters.printerSn });
    }

    if (filters.printType) {
      queryBuilder.andWhere('task.printType = :printType', { printType: filters.printType });
    }

    if (filters.printStatus) {
      queryBuilder.andWhere('task.printStatus = :printStatus', { printStatus: filters.printStatus });
    }

    if (filters.startDate) {
      queryBuilder.andWhere('task.createdAt >= :startDate', { startDate: filters.startDate });
    }

    if (filters.endDate) {
      queryBuilder.andWhere('task.createdAt <= :endDate', { endDate: filters.endDate });
    }

    // 应用搜索条件
    if (filters.search) {
      const searchTerm = `%${filters.search}%`;
      queryBuilder.andWhere(
        '(task.taskId LIKE :search OR CAST(task.orderId AS CHAR) LIKE :search OR task.printerSn LIKE :search)',
        { search: searchTerm }
      );
    }

    // 应用分页
    queryBuilder.skip((page - 1) * limit).take(limit);

    const [tasks, total] = await queryBuilder.getManyAndCount();

    return { tasks, total };
  }

  /**
   * 获取待处理的延迟打印任务
   * 包括DELAYED状态和PENDING状态的任务（向后兼容）
   */
  async getPendingDelayedTasks(tenantId: number): Promise<FeiePrintTaskMt[]> {
    return this.repository.find({
      where: [
        {
          tenantId,
          printStatus: PrintStatus.DELAYED,
          scheduledAt: LessThanOrEqual(new Date())
        },
        {
          tenantId,
          printStatus: PrintStatus.PENDING,
          scheduledAt: LessThanOrEqual(new Date())
        }
      ] as any,
      order: { scheduledAt: 'ASC' } as any
    });
  }

  /**
   * 处理退款事件，取消相关打印任务
   */
  async handleRefundEvent(tenantId: number, orderId: number): Promise<void> {
    const tasks = await this.repository.find({
      where: {
        tenantId,
        orderId,
        printStatus: PrintStatus.DELAYED
      } as any
    });

    for (const task of tasks) {
      await this.cancelPrintTask(tenantId, task.taskId, CancelReason.REFUND);
    }
  }

  /**
   * 生成任务ID
   */
  private generateTaskId(): string {
    const timestamp = Date.now();
    const random = Math.floor(Math.random() * 10000);
    return `FEIE_${timestamp}_${random}`;
  }
}
