import { ChatOpenAI } from '@langchain/openai';
import { SystemMessage, HumanMessage } from '@langchain/core/messages';
import { RunnableConfig } from '@langchain/core/runnables';
import { EvaluationState } from '../state';

/**
 * Node responsible for generating assessment questions based on the knowledge base content.
 */
export const questionGeneratorNode = async (
  state: EvaluationState,
  config?: RunnableConfig,
): Promise<Partial<EvaluationState>> => {
  const { model, knowledgeBaseContent } = (config?.configurable as any) || {};

  console.log('[GeneratorNode] Starting generation...', {
    language: state.language,
    hasModel: !!model,
    contentLength: knowledgeBaseContent?.length,
    keywords: state.keywords || [],
  });

  if (!model || !knowledgeBaseContent) {
    console.error('[GeneratorNode] Missing model or knowledgeBaseContent');
    throw new Error(
      'Missing model or knowledgeBaseContent in node configuration',
    );
  }

  const isZh = state.language === 'zh';
  const isJa = state.language === 'ja';

  const style = state.style || 'technical';
  const difficultyText = state.difficultyDistribution
    ? JSON.stringify(state.difficultyDistribution)
    : '随机分布 (Random distribution)';
  const keywords = state.keywords || [];
  const hasKeywords = keywords.length > 0;
  const keywordText = hasKeywords ? keywords.join(', ') : '';

  const rulesZh = [
    `**禁止重复**：绝对禁止生成与下方“禁止重复列表”中相似的题目。`,
    `**深度挖掘**：如果之前的题目考查了核心定义，新题目必须考查具体的应用案例、对比分析或隐藏的细节。`,
    hasKeywords
      ? `**关键词权重**：必须围绕关键词 (${keywordText}) 展开，但要从关键词的不同侧面（如流程、限制、优缺点、具体参数等）进行挖掘。`
      : null,
    `**随机扰动**：即使对于相同的主题或关键词，也要尝试从不同的逻辑链条（如“因为...所以...” vs “如果没有...会怎样”）出发。`,
  ]
    .filter(Boolean)
    .map((r, i) => `${i + 1}. ${r}`)
    .join('\n');

  const rulesJa = [
    `**重複禁止**：下記の「作成済み問題リスト」と類似した内容は絶対に避けてください。`,
    `**多角的アプローチ**：前回が定義だった場合は、今回は応用方法、制限事項、具体的な数値などに焦点を当ててください。`,
    hasKeywords
      ? `**キーワードの深掘り**：キーワード (${keywordText}) の異なる側面から出題してください。`
      : null,
  ]
    .filter(Boolean)
    .map((r, i) => `${i + 1}. ${r}`)
    .join('\n');

  const rulesEn = [
    `**NO REPETITION**: Strictly avoid any conceptual overlap with the "Previous Questions" list below.`,
    `**New Facets**: If previous questions were about definitions, focus on applications, edge cases, or specific details.`,
    hasKeywords
      ? `**Keyword Variety**: Center on (${keywordText}), but explore different aspects (process, pros/cons, requirements).`
      : null,
  ]
    .filter(Boolean)
    .map((r, i) => `${i + 1}. ${r}`)
    .join('\n');

  const existingQuestions = state.questions || [];
  const existingQuestionsText = existingQuestions
    .map((q, i) => `Q${i + 1}: ${q.questionText}`)
    .join('\n');

  const systemPromptZh = `你是一位专业的知识评估专家。请根据提供的知识库片段生成 1 个唯一的测试题目。

### 强制性多样性规则：
${rulesZh}

### 禁止重复列表（已出过）：
${existingQuestionsText || '无'}

### 任务：
${hasKeywords ? `目标关键词：${keywordText}\n` : ''}出题风格：${style}
难度：${difficultyText}

请以 JSON 数组格式返回 1 个问题：
[
  {
    "question_text": "...",
    "key_points": ["点1", "点2"],
    "difficulty": "...",
    "basis": "[n] 引用原文..."
  }
]`;

  const systemPromptJa = `あなたは専門的なアセスメントエキスパートです。提供されたナレッジベースに基づいて、ユニークな問題を 1 つ作成してください。

### 多様性ルール：
${rulesJa}

### 作成済み問題リスト：
${existingQuestionsText || 'なし'}

JSON 形式で 1 つ返してください。`;

  const systemPromptEn = `You are an expert examiner. Generate 1 UNIQUE question based on the provided context.

### Diversity Rules:
${rulesEn}

### Previous Questions (DO NOT REPEAT):
${existingQuestionsText || 'None'}

Return 1 question as a JSON array.`;

  const systemPrompt = isZh
    ? systemPromptZh
    : isJa
      ? systemPromptJa
      : systemPromptEn;
  const humanMsg = isZh
    ? `基于以下内容生成题目：\n\n${knowledgeBaseContent}`
    : isJa
      ? `以下の内容に基づいて作成してください：\n\n${knowledgeBaseContent}`
      : `Generate question based on:\n\n${knowledgeBaseContent}`;

  try {
    const response = await model.invoke([
      new SystemMessage(systemPrompt),
      new HumanMessage(humanMsg),
    ]);

    try {
      const newQuestions = JSON.parse(response.content as string);
      const mappedNewQuestions = newQuestions.map((q: any) => ({
        id: (existingQuestions.length + 1).toString(),
        questionText: q.question_text,
        keyPoints: q.key_points,
        difficulty: q.difficulty,
        basis: q.basis,
      }));

      return {
        questions: [...existingQuestions, ...mappedNewQuestions],
      };
    } catch (error) {
      console.error('[GeneratorNode] Parse error:', error);
      return { questions: existingQuestions };
    }
  } catch (invokeError) {
    console.error('[GeneratorNode] Invoke error:', invokeError);
    throw invokeError;
  }
};
