import {
  Injectable,
  Inject,
  NotFoundException,
  BadRequestException,
  Logger,
} from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { OssService } from '../oss/oss.service';
import { CreateTaskDto } from './dto/create-task.dto';
import { QueryTaskDto } from './dto/query-task.dto';
import { AI3DProvider, AI3D_PROVIDER } from './providers/ai-3d-provider.interface';

// 配置常量
const MAX_USER_TASKS = 3; // 每用户最大任务数（pending + processing）
const API_MAX_CONCURRENT = 3; // 混元API全局最大并发数（所有用户共享）
const TASK_TIMEOUT_MS = 10 * 60 * 1000; // 10分钟超时
const MAX_RETRY_COUNT = 3; // 最大重试次数
const QUEUE_CHECK_INTERVAL = 3000; // 队列检查间隔（毫秒）

@Injectable()
export class AI3DService {
  private readonly logger = new Logger(AI3DService.name);
  private queueCheckTimer: NodeJS.Timeout | null = null;
  private isProcessingQueue = false; // 防止并发处理队列

  constructor(
    private prisma: PrismaService,
    private ossService: OssService,
    @Inject(AI3D_PROVIDER) private ai3dProvider: AI3DProvider,
  ) {
    // 启动队列检查定时器
    this.startQueueChecker();
  }

  /**
   * 启动队列检查定时器
   */
  private startQueueChecker() {
    if (this.queueCheckTimer) return;

    this.queueCheckTimer = setInterval(async () => {
      await this.processQueuedTasks();
    }, QUEUE_CHECK_INTERVAL);

    this.logger.log('队列检查器已启动');
  }

  /**
   * 获取当前正在API执行的任务数（全局，所有用户）
   */
  private async getGlobalProcessingCount(): Promise<number> {
    return this.prisma.aI3DTask.count({
      where: {
        status: 'processing', // 只统计已提交到API的任务
      },
    });
  }

  /**
   * 处理排队中的任务
   */
  private async processQueuedTasks() {
    // 防止并发处理
    if (this.isProcessingQueue) return;
    this.isProcessingQueue = true;

    try {
      // 检查当前全局并发数
      const processingCount = await this.getGlobalProcessingCount();
      const availableSlots = API_MAX_CONCURRENT - processingCount;

      if (availableSlots <= 0) {
        return; // 没有可用槽位
      }

      // 获取等待中的任务（按创建时间排序，先进先出）
      const pendingTasks = await this.prisma.aI3DTask.findMany({
        where: { status: 'pending' },
        orderBy: { createTime: 'asc' },
        take: availableSlots,
      });

      if (pendingTasks.length === 0) return;

      this.logger.log(
        `队列处理: ${pendingTasks.length} 个任务待提交，可用槽位: ${availableSlots}`,
      );

      // 逐个提交任务
      for (const task of pendingTasks) {
        // 再次检查并发数（防止并发提交）
        const currentProcessing = await this.getGlobalProcessingCount();
        if (currentProcessing >= API_MAX_CONCURRENT) {
          this.logger.log('全局并发已满，停止提交');
          break;
        }

        await this.submitTaskToAPI(task);
      }
    } catch (error) {
      this.logger.error(`处理队列任务出错: ${error.message}`);
    } finally {
      this.isProcessingQueue = false;
    }
  }

  /**
   * 提交任务到混元API
   */
  private async submitTaskToAPI(task: any) {
    try {
      // 构建生成选项
      const options: any = {
        generateType: task.generateType,
      };

      const externalTaskId = await this.ai3dProvider.submitTask(
        task.inputType as 'text' | 'image',
        task.inputContent,
        options,
      );

      // 更新状态为处理中
      await this.prisma.aI3DTask.update({
        where: { id: task.id },
        data: {
          status: 'processing',
          externalTaskId,
        },
      });

      // 启动轮询检查任务状态
      this.pollTaskStatus(task.id, externalTaskId, Date.now());

      this.logger.log(`任务 ${task.id} 已提交到API，外部ID: ${externalTaskId}`);
    } catch (error) {
      // 提交失败，标记为失败
      await this.prisma.aI3DTask.update({
        where: { id: task.id },
        data: {
          status: 'failed',
          errorMessage: error.message || 'AI服务提交失败',
          completeTime: new Date(),
        },
      });
      this.logger.error(`任务 ${task.id} 提交API失败: ${error.message}`);
    }
  }

  /**
   * 创建生成任务
   */
  async createTask(
    userId: number,
    tenantId: number,
    dto: CreateTaskDto,
  ) {
    // 1. 检查用户当前任务数量（pending + processing）
    const userTaskCount = await this.prisma.aI3DTask.count({
      where: {
        userId,
        status: { in: ['pending', 'processing'] },
      },
    });

    if (userTaskCount >= MAX_USER_TASKS) {
      throw new BadRequestException(
        `您当前有 ${userTaskCount} 个任务正在排队或处理中，最多同时 ${MAX_USER_TASKS} 个任务，请等待完成后再提交`,
      );
    }

    // 2. 创建数据库记录（初始状态为 pending，表示排队中）
    const task = await this.prisma.aI3DTask.create({
      data: {
        userId,
        tenantId,
        inputType: dto.inputType,
        inputContent: dto.inputContent,
        generateType: dto.generateType || 'Normal',
        status: 'pending',
      },
    });

    this.logger.log(`任务 ${task.id} 已创建，进入队列`);

    // 3. 检查全局并发数，决定是立即提交还是等待队列处理
    const processingCount = await this.getGlobalProcessingCount();

    if (processingCount < API_MAX_CONCURRENT) {
      // 有空闲槽位，立即提交
      try {
        // 构建生成选项
        const options: any = {
          generateType: dto.generateType,
          faceCount: dto.faceCount,
        };

        // 处理多视图图片（图生3D支持）
        if (dto.inputType === 'image' && dto.multiViewImages) {
          const viewKeyMap: Record<string, string> = {
            left: 'left',
            right: 'right',
            back: 'back',
            top: 'top',
            bottom: 'bottom',
            left45: 'left_front',
            right45: 'right_front',
          };

          const multiViewImages: { viewType: string; imageUrl: string }[] = [];
          for (const [key, url] of Object.entries(dto.multiViewImages)) {
            if (url && key !== 'front' && viewKeyMap[key]) {
              multiViewImages.push({
                viewType: viewKeyMap[key],
                imageUrl: url,
              });
            }
          }

          if (multiViewImages.length > 0) {
            options.multiViewImages = multiViewImages;
            this.logger.log(`多视图模式: ${multiViewImages.length} 张额外视图`);
          }
        }

        const externalTaskId = await this.ai3dProvider.submitTask(
          dto.inputType,
          dto.inputContent,
          options,
        );

        // 更新状态为处理中
        await this.prisma.aI3DTask.update({
          where: { id: task.id },
          data: {
            status: 'processing',
            externalTaskId,
          },
        });

        // 启动轮询检查任务状态
        this.pollTaskStatus(task.id, externalTaskId, Date.now());

        this.logger.log(`任务 ${task.id} 已提交到API，外部ID: ${externalTaskId}`);
      } catch (error) {
        // 提交失败，标记为失败
        await this.prisma.aI3DTask.update({
          where: { id: task.id },
          data: {
            status: 'failed',
            errorMessage: error.message || 'AI服务提交失败',
            completeTime: new Date(),
          },
        });
        this.logger.error(`任务 ${task.id} 提交失败: ${error.message}`);
        throw error;
      }
    } else {
      // 全局并发已满，任务保持 pending 状态，等待队列调度
      this.logger.log(
        `全局并发已满 (${processingCount}/${API_MAX_CONCURRENT})，任务 ${task.id} 进入排队`,
      );
    }

    return this.getTask(userId, task.id);
  }

  /**
   * 获取任务列表
   */
  async getTasks(userId: number, query: QueryTaskDto) {
    const { page = 1, pageSize = 10, status } = query;

    const where: any = { userId };
    if (status) {
      where.status = status;
    }

    const [list, total] = await Promise.all([
      this.prisma.aI3DTask.findMany({
        where,
        skip: (page - 1) * pageSize,
        take: pageSize,
        orderBy: { createTime: 'desc' },
      }),
      this.prisma.aI3DTask.count({ where }),
    ]);

    return {
      list,
      total,
      page,
      pageSize,
    };
  }

  /**
   * 获取任务详情
   */
  async getTask(userId: number, id: number) {
    const task = await this.prisma.aI3DTask.findFirst({
      where: { id, userId },
    });

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

    // 如果任务在排队中，计算队列位置
    if (task.status === 'pending') {
      const queuePosition = await this.getQueuePosition(task.id, task.createTime);
      return {
        ...task,
        queuePosition,
      };
    }

    return task;
  }

  /**
   * 获取任务在队列中的位置
   */
  private async getQueuePosition(taskId: number, createTime: Date): Promise<number> {
    // 统计在当前任务之前创建的、仍在排队的任务数量
    const position = await this.prisma.aI3DTask.count({
      where: {
        status: 'pending',
        createTime: { lte: createTime },
      },
    });
    return position;
  }

  /**
   * 删除任务
   */
  async deleteTask(userId: number, id: number) {
    const task = await this.getTask(userId, id);

    await this.prisma.aI3DTask.delete({
      where: { id: task.id },
    });

    this.logger.log(`任务 ${id} 已删除`);

    return null;
  }

  /**
   * 重试任务
   */
  async retryTask(userId: number, id: number) {
    const task = await this.prisma.aI3DTask.findFirst({
      where: { id, userId },
    });

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

    // 只有失败或超时的任务可以重试
    if (!['failed', 'timeout'].includes(task.status)) {
      throw new BadRequestException('只有失败或超时的任务可以重试');
    }

    // 检查重试次数
    if (task.retryCount >= MAX_RETRY_COUNT) {
      throw new BadRequestException(
        `已达到最大重试次数 ${MAX_RETRY_COUNT} 次，请创建新任务`,
      );
    }

    // 检查用户任务数限制
    const userTaskCount = await this.prisma.aI3DTask.count({
      where: {
        userId,
        status: { in: ['pending', 'processing'] },
      },
    });

    if (userTaskCount >= MAX_USER_TASKS) {
      throw new BadRequestException(
        `您当前有 ${userTaskCount} 个任务正在排队或处理中，请等待完成后再重试`,
      );
    }

    // 重置任务状态为 pending（进入队列）
    await this.prisma.aI3DTask.update({
      where: { id },
      data: {
        status: 'pending',
        errorMessage: null,
        completeTime: null,
        externalTaskId: null,
        retryCount: { increment: 1 },
      },
    });

    this.logger.log(`任务 ${id} 已重新加入队列，等待处理`);

    // 检查是否可以立即提交
    const processingCount = await this.getGlobalProcessingCount();
    if (processingCount < API_MAX_CONCURRENT) {
      // 有空闲槽位，立即提交
      const updatedTask = await this.prisma.aI3DTask.findUnique({
        where: { id },
      });
      if (updatedTask) {
        await this.submitTaskToAPI(updatedTask);
      }
    }

    return this.getTask(userId, id);
  }

  /**
   * 轮询检查任务状态
   */
  private async pollTaskStatus(
    taskId: number,
    externalTaskId: string,
    startTime: number,
  ) {
    const checkStatus = async () => {
      // 1. 检查是否超时
      if (Date.now() - startTime > TASK_TIMEOUT_MS) {
        await this.prisma.aI3DTask.update({
          where: { id: taskId },
          data: {
            status: 'timeout',
            errorMessage: '任务处理超时，请重试',
            completeTime: new Date(),
          },
        });
        this.logger.warn(`任务 ${taskId} 超时`);
        return;
      }

      // 2. 查询外部任务状态
      try {
        const result = await this.ai3dProvider.queryTask(externalTaskId);

        if (result.status === 'completed' || result.status === 'failed') {
          let finalResultUrl = result.resultUrl;
          let finalPreviewUrl = result.previewUrl;
          let finalResultUrls = result.resultUrls || null;
          let finalPreviewUrls = result.previewUrls || null;

          // 3. 如果任务成功且COS已启用，转存文件到自己的COS
          if (result.status === 'completed' && this.ossService.isEnabled()) {
            try {
              // 转存所有模型文件
              if (result.resultUrls && result.resultUrls.length > 0) {
                this.logger.log(`开始转存 ${result.resultUrls.length} 个模型文件到COS: ${taskId}`);
                const uploadedModelUrls: string[] = [];
                for (let i = 0; i < result.resultUrls.length; i++) {
                  const modelResult = await this.ossService.uploadAI3DModel(
                    result.resultUrls[i],
                    taskId,
                    i,
                  );
                  uploadedModelUrls.push(modelResult.modelUrl);
                  this.logger.log(`模型文件 ${i + 1} 转存完成: ${modelResult.modelUrl}`);
                }
                finalResultUrl = uploadedModelUrls[0];
                finalResultUrls = uploadedModelUrls;
              }

              // 转存所有预览图
              if (result.previewUrls && result.previewUrls.length > 0) {
                this.logger.log(`开始转存 ${result.previewUrls.length} 个预览图到COS: ${taskId}`);
                const uploadedPreviewUrls: string[] = [];
                for (let i = 0; i < result.previewUrls.length; i++) {
                  const previewResult = await this.ossService.uploadAI3DPreview(
                    result.previewUrls[i],
                    taskId,
                    i,
                  );
                  uploadedPreviewUrls.push(previewResult.previewUrl);
                  this.logger.log(`预览图 ${i + 1} 转存完成: ${previewResult.previewUrl}`);
                }
                finalPreviewUrl = uploadedPreviewUrls[0];
                finalPreviewUrls = uploadedPreviewUrls;
              }
            } catch (transferError) {
              // 转存失败不影响任务完成，只记录日志
              this.logger.error(
                `文件转存失败，使用原始URL: ${transferError.message}`,
              );
            }
          }

          await this.prisma.aI3DTask.update({
            where: { id: taskId },
            data: {
              status: result.status,
              resultUrl: finalResultUrl,
              previewUrl: finalPreviewUrl,
              resultUrls: finalResultUrls,
              previewUrls: finalPreviewUrls,
              errorMessage: result.errorMessage,
              completeTime: new Date(),
            },
          });

          this.logger.log(
            `任务 ${taskId} ${result.status === 'completed' ? '完成' : '失败'}`,
          );
        } else {
          // 继续轮询，每2秒检查一次
          setTimeout(checkStatus, 2000);
        }
      } catch (error) {
        this.logger.error(`轮询任务 ${taskId} 状态出错: ${error.message}`);
        // 出错后延长轮询间隔，每5秒重试
        setTimeout(checkStatus, 5000);
      }
    };

    // 首次检查延迟2秒
    setTimeout(checkStatus, 2000);
  }
}
