import { prisma } from '../../config/database.js';
import { extractionClient } from '../../common/document/ExtractionClient.js';
import { LLMFactory } from '../../common/llm/adapters/LLMFactory.js';
import { ModelType } from '../../common/llm/adapters/types.js';
import fs from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

/**
 * 稿件审查服务
 */

// ==================== 类型定义 ====================

export interface EditorialItem {
  criterion: string;
  status: 'pass' | 'warning' | 'fail';
  score: number;
  issues: string[];
  suggestions: string[];
}

export interface EditorialReview {
  overall_score: number;
  summary: string;
  items: EditorialItem[];
}

export interface MethodologyIssue {
  type: string;
  severity: 'major' | 'minor';
  description: string;
  location: string;
  suggestion: string;
}

export interface MethodologyPart {
  part: string;
  score: number;
  issues: MethodologyIssue[];
}

export interface MethodologyReview {
  overall_score: number;
  summary: string;
  parts: MethodologyPart[];
}

// ==================== 主要功能函数 ====================

/**
 * 审查稿件（主入口函数）
 * @param file 文件Buffer
 * @param filename 文件名
 * @param userId 用户ID
 * @param modelType 模型类型
 * @returns 审查任务
 */
export async function reviewManuscript(
  file: Buffer,
  filename: string,
  userId: string,
  modelType: ModelType = 'deepseek-v3'
) {
  const startTime = Date.now();

  // 1. 创建任务记录
  const task = await prisma.reviewTask.create({
    data: {
      userId,
      fileName: filename,
      fileSize: file.length,
      extractedText: '', // 初始为空
      status: 'pending',
      modelUsed: modelType,
      startedAt: new Date(),
    },
  });

  try {
    // 2. 提取文档文本（异步执行，不阻塞响应）
    processReviewTask(task.id, file, filename, userId, modelType, startTime).catch(error => {
      console.error(`[ReviewService] Task ${task.id} failed:`, error);
    });

    return task;
  } catch (error) {
    // 如果任务创建失败，更新状态
    await prisma.reviewTask.update({
      where: { id: task.id },
      data: {
        status: 'failed',
        errorMessage: error instanceof Error ? error.message : 'Unknown error',
      },
    });
    throw error;
  }
}

/**
 * 处理审查任务（后台异步执行）
 */
async function processReviewTask(
  taskId: string,
  file: Buffer,
  filename: string,
  userId: string,
  modelType: ModelType,
  startTime: number
) {
  try {
    // 1. 更新状态为extracting
    await prisma.reviewTask.update({
      where: { id: taskId },
      data: { status: 'extracting' },
    });

    // 2. 提取文档文本
    console.log(`[ReviewService] 开始提取文档: ${filename}`);
    const extractionResult = await extractionClient.extractDocument(file, filename);

    if (!extractionResult.success || !extractionResult.text) {
      throw new Error('文档提取失败或内容为空');
    }

    const extractedText = extractionResult.text;
    const wordCount = extractionResult.metadata?.char_count || extractedText.length;

    console.log(`[ReviewService] 提取成功: ${wordCount} 字符`);

    // 更新提取的文本
    await prisma.reviewTask.update({
      where: { id: taskId },
      data: {
        extractedText,
        wordCount,
        status: 'reviewing_editorial',
      },
    });

    // 3. 执行稿约规范性评估
    console.log(`[ReviewService] 开始稿约规范性评估...`);
    const editorialReview = await reviewEditorialStandards(extractedText, modelType);

    await prisma.reviewTask.update({
      where: { id: taskId },
      data: {
        editorialReview: editorialReview as any,
        status: 'reviewing_methodology',
      },
    });

    // 4. 执行方法学评估
    console.log(`[ReviewService] 开始方法学评估...`);
    const methodologyReview = await reviewMethodology(extractedText, modelType);

    // 5. 计算总体评分（加权平均：稿约40% + 方法学60%）
    const overallScore = editorialReview.overall_score * 0.4 + methodologyReview.overall_score * 0.6;

    // 6. 完成任务
    const endTime = Date.now();
    const durationSeconds = Math.floor((endTime - startTime) / 1000);

    await prisma.reviewTask.update({
      where: { id: taskId },
      data: {
        methodologyReview: methodologyReview as any,
        overallScore,
        status: 'completed',
        completedAt: new Date(),
        durationSeconds,
      },
    });

    console.log(`[ReviewService] 任务完成: ${taskId}, 总分: ${overallScore.toFixed(1)}, 耗时: ${durationSeconds}s`);
  } catch (error) {
    console.error(`[ReviewService] 任务处理失败:`, error);

    // 更新任务状态为failed
    await prisma.reviewTask.update({
      where: { id: taskId },
      data: {
        status: 'failed',
        errorMessage: error instanceof Error ? error.message : 'Unknown error',
      },
    });
  }
}

/**
 * 稿约规范性评估
 * @param text 稿件文本
 * @param modelType 模型类型
 * @returns 评估结果
 */
export async function reviewEditorialStandards(
  text: string,
  modelType: ModelType = 'deepseek-v3'
): Promise<EditorialReview> {
  try {
    // 1. 读取系统Prompt
    const promptPath = path.join(__dirname, '../../../prompts/review_editorial_system.txt');
    const systemPrompt = await fs.readFile(promptPath, 'utf-8');

    // 2. 构建消息
    const messages = [
      { role: 'system' as const, content: systemPrompt },
      { role: 'user' as const, content: `请对以下稿件进行稿约规范性评估：\n\n${text}` },
    ];

    // 3. 调用LLM
    console.log(`[ReviewService] 开始调用 ${modelType} 进行稿约规范性评估...`);
    const llmAdapter = LLMFactory.getAdapter(modelType);
    const response = await llmAdapter.chat(messages, {
      temperature: 0.3, // 较低温度以获得更稳定的评估
      maxTokens: 8000, // 增加token限制，确保完整输出
    });
    console.log(`[ReviewService] ${modelType} 稿约规范性评估完成，响应长度: ${response.content.length}`);

    // 4. 解析JSON响应
    const result = parseJSONFromLLMResponse<EditorialReview>(response.content);

    // 5. 验证响应格式
    if (!result || typeof result.overall_score !== 'number' || !Array.isArray(result.items)) {
      throw new Error('LLM返回的数据格式不正确');
    }

    return result;
  } catch (error) {
    console.error('[ReviewService] 稿约规范性评估失败:', error);
    if (error instanceof Error) {
      console.error('[ReviewService] 错误详情:', {
        message: error.message,
        stack: error.stack,
      });
    }
    throw new Error(`稿约规范性评估失败: ${error instanceof Error ? error.message : 'Unknown error'}`);
  }
}

/**
 * 方法学评估
 * @param text 稿件文本
 * @param modelType 模型类型
 * @returns 评估结果
 */
export async function reviewMethodology(
  text: string,
  modelType: ModelType = 'deepseek-v3'
): Promise<MethodologyReview> {
  try {
    // 1. 读取系统Prompt
    const promptPath = path.join(__dirname, '../../../prompts/review_methodology_system.txt');
    const systemPrompt = await fs.readFile(promptPath, 'utf-8');

    // 2. 构建消息
    const messages = [
      { role: 'system' as const, content: systemPrompt },
      { role: 'user' as const, content: `请对以下稿件进行方法学评估：\n\n${text}` },
    ];

    // 3. 调用LLM
    console.log(`[ReviewService] 开始调用 ${modelType} 进行方法学评估...`);
    const llmAdapter = LLMFactory.getAdapter(modelType);
    const response = await llmAdapter.chat(messages, {
      temperature: 0.3,
      maxTokens: 8000, // 增加token限制，确保完整输出
    });
    console.log(`[ReviewService] ${modelType} 方法学评估完成，响应长度: ${response.content.length}`);

    // 4. 解析JSON响应
    const result = parseJSONFromLLMResponse<MethodologyReview>(response.content);

    // 5. 验证响应格式
    if (!result || typeof result.overall_score !== 'number' || !Array.isArray(result.parts)) {
      throw new Error('LLM返回的数据格式不正确');
    }

    return result;
  } catch (error) {
    console.error('[ReviewService] 方法学评估失败:', error);
    if (error instanceof Error) {
      console.error('[ReviewService] 错误详情:', {
        message: error.message,
        stack: error.stack,
      });
    }
    throw new Error(`方法学评估失败: ${error instanceof Error ? error.message : 'Unknown error'}`);
  }
}

/**
 * 从LLM响应中解析JSON
 * 支持多种格式：纯JSON、```json代码块、混合文本
 */
function parseJSONFromLLMResponse<T>(content: string): T {
  try {
    // 1. 尝试直接解析
    return JSON.parse(content) as T;
  } catch {
    // 2. 尝试提取```json代码块
    const jsonMatch = content.match(/```json\s*\n?([\s\S]*?)\n?```/);
    if (jsonMatch) {
      try {
        return JSON.parse(jsonMatch[1].trim()) as T;
      } catch {
        // 继续尝试其他方法
      }
    }

    // 3. 尝试提取{}或[]包裹的内容
    const objectMatch = content.match(/(\{[\s\S]*\})/);
    if (objectMatch) {
      try {
        return JSON.parse(objectMatch[1]) as T;
      } catch {
        // 继续尝试其他方法
      }
    }

    const arrayMatch = content.match(/(\[[\s\S]*\])/);
    if (arrayMatch) {
      try {
        return JSON.parse(arrayMatch[1]) as T;
      } catch {
        // 失败
      }
    }

    // 4. 所有尝试都失败
    throw new Error('无法从LLM响应中解析JSON');
  }
}

// ==================== 任务查询与管理 ====================

/**
 * 获取任务详情
 */
export async function getReviewTask(userId: string, taskId: string) {
  const task = await prisma.reviewTask.findFirst({
    where: {
      id: taskId,
      userId,
    },
  });

  if (!task) {
    throw new Error('Task not found or access denied');
  }

  return task;
}

/**
 * 获取用户的所有审查任务
 */
export async function getReviewTasks(userId: string, page: number = 1, limit: number = 20) {
  const skip = (page - 1) * limit;

  const [tasks, total] = await Promise.all([
    prisma.reviewTask.findMany({
      where: { userId },
      orderBy: { createdAt: 'desc' },
      skip,
      take: limit,
      select: {
        id: true,
        fileName: true,
        fileSize: true,
        status: true,
        overallScore: true,
        modelUsed: true,
        createdAt: true,
        completedAt: true,
        durationSeconds: true,
        wordCount: true,
      },
    }),
    prisma.reviewTask.count({
      where: { userId },
    }),
  ]);

  return {
    tasks,
    pagination: {
      page,
      limit,
      total,
      totalPages: Math.ceil(total / limit),
    },
  };
}

/**
 * 删除审查任务
 */
export async function deleteReviewTask(userId: string, taskId: string) {
  const task = await prisma.reviewTask.findFirst({
    where: {
      id: taskId,
      userId,
    },
  });

  if (!task) {
    throw new Error('Task not found or access denied');
  }

  await prisma.reviewTask.delete({
    where: { id: taskId },
  });

  return { success: true };
}

/**
 * 获取任务报告（完整的评估结果）
 */
export async function getReviewReport(userId: string, taskId: string) {
  const task = await prisma.reviewTask.findFirst({
    where: {
      id: taskId,
      userId,
    },
  });

  if (!task) {
    throw new Error('Task not found or access denied');
  }

  if (task.status !== 'completed') {
    throw new Error('Report is not ready yet. Task status: ' + task.status);
  }

  return {
    taskId: task.id,
    fileName: task.fileName,
    wordCount: task.wordCount,
    modelUsed: task.modelUsed,
    overallScore: task.overallScore,
    editorialReview: task.editorialReview,
    methodologyReview: task.methodologyReview,
    completedAt: task.completedAt,
    durationSeconds: task.durationSeconds,
  };
}

