/**
 * 智能容错层 - 为书籍生成提供稳定性保障
 *
 * 核心功能：
 * 1. AI调用重试机制（3次重试 + 指数退避）
 * 2. 节点级超时控制（超时自动跳过或降级）
 * 3. 进度监控和长时间无响应告警
 * 4. 失败自动恢复（智能重试策略）
 */

import { bookStore } from './book-generator.store';
import { callLLMWithMessages, ChatMessage } from '../../services/llm';

// ============ 配置 ============

export const FAULT_TOLERANCE_CONFIG = {
  // AI调用重试
  aiRetry: {
    maxRetries: 3,              // 最大重试次数
    initialDelayMs: 2000,       // 初始延迟 2秒
    maxDelayMs: 30000,          // 最大延迟 30秒
    backoffMultiplier: 2,       // 指数退避倍数
  },
  
  // 节点超时
  nodeTimeout: {
    deep_plan: 3 * 60 * 1000,          // 深度规划：3分钟
    generate_outline: 5 * 60 * 1000,    // 大纲生成：5分钟
    rich_outline: 8 * 60 * 1000,        // 富信息大纲：8分钟
    generate_sections: 10 * 60 * 1000,  // 节生成：10分钟
    generate_subsections: 15 * 60 * 1000, // 小节生成：15分钟
    write_chapters: 30 * 60 * 1000,     // 内容生成：30分钟
    parallel_content: 45 * 60 * 1000,   // 并行内容生成：45分钟（8路并发）
    continuity_edit: 10 * 60 * 1000,    // 连贯性编辑：10分钟
    quality_check: 10 * 60 * 1000,     // 质量校验：10分钟
    rewrite: 15 * 60 * 1000,           // 改写优化：15分钟
    write_foreword: 5 * 60 * 1000,      // 前言：5分钟
    write_afterword: 5 * 60 * 1000,     // 后记：5分钟
  },
  
  // 进度监控
  progressMonitor: {
    maxIdleTimeMs: 10 * 60 * 1000,  // 最大空闲时间 10分钟
    checkIntervalMs: 60 * 1000,     // 检查间隔 1分钟
  },
  
  // 自动恢复
  autoRecovery: {
    maxRecoveryAttempts: 2,         // 最大恢复尝试次数
    recoveryDelayMs: 5 * 60 * 1000, // 恢复延迟 5分钟
  },
};

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

export interface FaultToleranceContext {
  bookId: string;
  nodeId: string;
  attempt: number;
  maxAttempts: number;
}

// ============ AI调用重试包装器 ============

/**
 * 带重试机制的AI调用
 * 失败后自动重试，使用指数退避策略
 */
export async function callLLMWithRetry(
  messages: ChatMessage[],
  modelId: string | undefined,
  context: FaultToleranceContext,
  maxTokens?: number
): Promise<string> {
  const { bookId, nodeId, attempt, maxAttempts } = context;
  const config = FAULT_TOLERANCE_CONFIG.aiRetry;
  
  let lastError: Error | null = null;
  
  for (let i = 0; i <= maxAttempts; i++) {
    try {
      // 第一次不显示重试日志
      if (i > 0) {
        const delay = Math.min(
          config.initialDelayMs * Math.pow(config.backoffMultiplier, i - 1),
          config.maxDelayMs
        );
        
        console.log(`[容错] AI调用重试 ${i}/${maxAttempts}，等待 ${delay/1000}秒后重试...`);
        await sleep(delay);
        
        // 通知用户正在重试
        await notifyUser(bookId, {
          type: 'ai_retry',
          nodeId,
          attempt: i,
          maxAttempts,
          message: `AI调用失败，正在重试 (${i}/${maxAttempts})...`,
        });
      }
      
      return await callLLMWithMessages(messages, modelId, maxTokens);
    } catch (error: any) {
      lastError = error;
      console.error(`[容错] AI调用失败 (attempt ${i + 1}/${maxAttempts + 1}):`, error.message);
      
      // 记录失败到数据库
      await logAIFailure(bookId, nodeId, error.message, i + 1);
    }
  }
  
  // 所有重试都失败了
  const finalError = new Error(`AI调用失败，已重试${maxAttempts}次: ${lastError?.message}`);
  console.error(`[容错] ❌ AI调用最终失败:`, finalError.message);
  
  // 通知用户AI调用失败
  await notifyUser(bookId, {
    type: 'ai_failed',
    nodeId,
    message: `AI调用失败，已重试${maxAttempts}次。系统将尝试自动恢复。`,
    error: lastError?.message,
  });
  
  throw finalError;
}

// ============ 节点超时控制 ============

/**
 * 带超时控制的节点执行
 * 超时后根据策略处理（跳过/降级/标记失败）
 */
export async function executeNodeWithTimeout<T>(
  bookId: string,
  nodeId: string,
  nodeFn: () => Promise<T>,
  timeoutMs?: number
): Promise<T> {
  const timeout = timeoutMs || FAULT_TOLERANCE_CONFIG.nodeTimeout[nodeId] || 10 * 60 * 1000;
  
  console.log(`[容错] 执行节点 ${nodeId}，超时时间: ${timeout/1000}秒`);
  
  // 通知用户节点开始执行
  await notifyUser(bookId, {
    type: 'node_start',
    nodeId,
    message: `正在执行: ${getNodeDisplayName(nodeId)}`,
  });
  
  return new Promise<T>((resolve, reject) => {
    const timeoutId = setTimeout(async () => {
      console.error(`[容错] ⚠️ 节点 ${nodeId} 执行超时 (${timeout/1000}秒)`);
      
      // 通知用户超时
      await notifyUser(bookId, {
        type: 'node_timeout',
        nodeId,
        message: `节点执行超时 (${timeout/1000}秒)，系统将尝试恢复...`,
      });
      
      reject(new Error(`节点 ${nodeId} 执行超时`));
    }, timeout);
    
    nodeFn()
      .then((result) => {
        clearTimeout(timeoutId);
        
        // 通知用户节点完成
        notifyUser(bookId, {
          type: 'node_complete',
          nodeId,
          message: `节点完成: ${getNodeDisplayName(nodeId)}`,
        }).catch(err => console.error('[容错] 通知用户失败:', err));
        
        resolve(result);
      })
      .catch((error) => {
        clearTimeout(timeoutId);
        reject(error);
      });
  });
}

// ============ 进度监控 ============

/**
 * 启动进度监控器
 * 检测长时间无响应的任务
 */
export function startProgressMonitor(bookId: string) {
  const config = FAULT_TOLERANCE_CONFIG.progressMonitor;
  let lastProgressTime = Date.now();
  let lastProgress = 0;
  let idleWarnings = 0;
  
  const monitorInterval = setInterval(async () => {
    try {
      // 从数据库获取最新进度
      const book = await bookStore.getById(bookId);
      if (!book) {
        clearInterval(monitorInterval);
        return;
      }
      
      const currentProgress = book.progress || 0;
      
      // 如果进度有更新，重置计数器
      if (currentProgress > lastProgress) {
        lastProgress = currentProgress;
        lastProgressTime = Date.now();
        idleWarnings = 0;
        return;
      }
      
      // 检查是否超时
      const idleTime = Date.now() - lastProgressTime;
      if (idleTime > config.maxIdleTimeMs) {
        idleWarnings++;
        
        console.warn(`[容错] ⚠️ 任务长时间无响应: bookId=${bookId}, 空闲时间=${idleTime/1000}秒`);
        
        // 第一次警告
        if (idleWarnings === 1) {
          await notifyUser(bookId, {
            type: 'progress_warning',
            message: '生成进度长时间未更新，系统正在监控中...',
            idleTime: Math.round(idleTime / 1000 / 60), // 分钟
          });
        }
        
        // 第二次警告，建议用户手动干预
        if (idleWarnings === 2) {
          await notifyUser(bookId, {
            type: 'progress_critical',
            message: '生成任务可能已卡住，建议刷新页面或重新生成',
            idleTime: Math.round(idleTime / 1000 / 60),
          });
        }
        
        // 第三次，尝试自动恢复
        if (idleWarnings >= 3) {
          console.error(`[容错] ❌ 任务长时间无响应，尝试自动恢复...`);
          clearInterval(monitorInterval);
          
          await notifyUser(bookId, {
            type: 'auto_recovery',
            message: '系统检测到任务异常，正在尝试自动恢复...',
          });
          
          await attemptAutoRecovery(bookId);
        }
      }
    } catch (error) {
      console.error('[容错] 进度监控失败:', error);
    }
  }, config.checkIntervalMs);
  
  // 返回停止函数
  return () => {
    clearInterval(monitorInterval);
    console.log(`[容错] 进度监控已停止: bookId=${bookId}`);
  };
}

// ============ 自动恢复机制 ============

/**
 * 尝试自动恢复失败的任务
 */
export async function attemptAutoRecovery(bookId: string) {
  const config = FAULT_TOLERANCE_CONFIG.autoRecovery;
  
  try {
    // 获取书籍当前状态
    const book: any = await bookStore.getById(bookId);
    if (!book) return;
    
    // 检查是否已经超过最大恢复次数（从errorMsg中判断）
    const errorCount = (book.errorMsg || '').match(/自动恢复/g)?.length || 0;
    if (errorCount >= config.maxRecoveryAttempts) {
      console.error(`[容错] ❌ 已达到最大恢复次数 (${config.maxRecoveryAttempts})，放弃恢复`);
      
      await notifyUser(bookId, {
        type: 'recovery_failed',
        message: `自动恢复失败（已尝试${config.maxRecoveryAttempts}次），请手动重新生成`,
      });
      
      // 标记为最终失败
      await bookStore.update(bookId, {
        genStage: 'failed',
        errorMsg: `生成失败，已尝试自动恢复${config.maxRecoveryAttempts}次`,
      });
      
      return;
    }
    
    console.log(`[容错] 🔄 尝试自动恢复 (第${errorCount + 1}次)...`);
    
    // 等待一段时间后重试
    await sleep(config.recoveryDelayMs);
    
    // 直接重新生成（跳过队列，数据库驱动更可靠）
    const { langGraphGenerator } = await import('./index.js');
    langGraphGenerator.generate(
      bookId,
      book.description || book.title,
      book.bookScale || '1000'
    ).then(() => {
      console.log(`[容错] ✅ 自动恢复成功: bookId=${bookId}`);
    }).catch(err => {
      console.error(`[容错] ❌ 自动恢复失败: bookId=${bookId}`, err);
    });
    
    await notifyUser(bookId, {
      type: 'recovery_success',
      message: '系统已自动恢复生成任务，请耐心等待...',
    });
  } catch (error) {
    console.error('[容错] 自动恢复失败:', error);
    
    await notifyUser(bookId, {
      type: 'recovery_error',
      message: '自动恢复失败，请手动重新生成',
      error: error instanceof Error ? error.message : '未知错误',
    });
  }
}

// ============ 用户通知 ============

export interface UserNotification {
  type: 'ai_retry' | 'ai_failed' | 'node_start' | 'node_complete' | 'node_timeout' |
        'progress_warning' | 'progress_critical' | 'auto_recovery' | 
        'recovery_success' | 'recovery_failed' | 'recovery_error';
  nodeId?: string;
  attempt?: number;
  maxAttempts?: number;
  message: string;
  error?: string;
  idleTime?: number;
  jobId?: string;
}

/**
 * 记录用户通知（客户端通过轮询获取状态）
 */
async function notifyUser(bookId: string, notification: UserNotification) {
  console.log(`[容错] 📢 通知: ${notification.type} - ${notification.message} (bookId: ${bookId})`);
}

// ============ 失败日志 ============

/**
 * 记录AI调用失败到数据库
 */
async function logAIFailure(bookId: string, nodeId: string, errorMessage: string, attempt: number) {
  try {
    // 目前先记录到errorMsg字段
    const book: any = await bookStore.getById(bookId);
    const existingErrors = book.errorMsg ? `${book.errorMsg}\n` : '';
    
    await bookStore.update(bookId, {
      errorMsg: `${existingErrors}[${new Date().toISOString()}] ${nodeId} 失败 (尝试${attempt}次): ${errorMessage}`,
    } as any);
  } catch (error) {
    console.error('[容错] 记录失败日志失败:', error);
  }
}

// ============ 辅助函数 ============

function sleep(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms));
}

function getNodeDisplayName(nodeId: string): string {
  const names: Record<string, string> = {
    deep_plan: '深度规划',
    generate_outline: '生成章大纲',
    rich_outline: '生成富信息大纲',
    generate_sections: '生成节大纲',
    generate_subsections: '生成小节大纲',
    write_chapters: '生成章节内容',
    parallel_content: '并行生成章节内容',
    continuity_edit: '连贯性编辑',
    quality_check: '质量校验',
    rewrite: '改写优化',
    write_foreword: '生成前言',
    write_afterword: '生成后记',
  };
  return names[nodeId] || nodeId;
}
