/**
 * Utils 模块导出
 */

// 日志系统
const { Logger, logger, LOG_LEVELS } = require('./logger');

// ID 生成器
const {
  uuid,
  prefixedId,
  shortId,
  snowflake,
  taskId,
  goalId,
  sessionId,
  messageId,
  ruleId,
  resetSnowflake,
} = require('./id');

// 错误处理
const {
  FolikoError,
  PluginError,
  ToolError,
  AIError,
  SessionError,
  ConfigError,
  WorkflowError,
  ValidationError,
  ToolNotFoundError,
  PluginNotFoundError,
  isErrorOfType,
  safeErrorInfo,
} = require('./error');

// 重试策略
const { withRetry, retryable, isNetworkError, PRESETS } = require('./retry');

// 错误边界
const {
  ErrorBoundary,
  Severity,
  RecoveryAction,
  createErrorBoundary,
  combineBoundaries,
} = require('./error-boundary');

/**
 * 清理 LLM 回复中的思考标记
 * @param {string} text
 * @returns {string}
 */
function cleanResponse(text) {
  return text.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
}

/**
 * 安全解析 JSON
 * @param {string} str
 * @param {*} defaultValue
 * @returns {*}
 */
function safeJsonParse(str, defaultValue = null) {
  try {
    return JSON.parse(str);
  } catch {
    return defaultValue;
  }
}

/**
 * 深拷贝
 * @param {*} obj
 * @returns {*}
 */
function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') return obj;
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof Array) return obj.map((item) => deepClone(item));
  if (obj instanceof Object) {
    const copy = {};
    for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        copy[key] = deepClone(obj[key]);
      }
    }
    return copy;
  }
  return obj;
}

/**
 * 防抖函数
 * @param {Function} fn
 * @param {number} delay
 * @returns {Function}
 */
function debounce(fn, delay) {
  let timeoutId;
  return function (...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => fn.apply(this, args), delay);
  };
}

/**
 * 节流函数
 * @param {Function} fn
 * @param {number} limit
 * @returns {Function}
 */
function throttle(fn, limit) {
  let inThrottle;
  return function (...args) {
    if (!inThrottle) {
      fn.apply(this, args);
      inThrottle = true;
      setTimeout(() => (inThrottle = false), limit);
    }
  };
}

/**
 * 延迟执行
 * @param {number} ms
 * @returns {Promise}
 */
function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

/**
 * 重试函数
 * @param {Function} fn
 * @param {Object} options
 * @returns {Promise}
 */
async function retry(fn, options = {}) {
  const { maxAttempts = 3, delay = 1000, backoff = 2, onRetry } = options;

  let lastError;

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (error) {
      lastError = error;

      if (attempt < maxAttempts) {
        const waitTime = delay * Math.pow(backoff, attempt - 1);
        if (onRetry) {
          onRetry(attempt, waitTime, error);
        }
        await sleep(waitTime);
      }
    }
  }

  throw lastError;
}

/**
 * 安全序列化工具结果，移除循环引用
 * 处理 Error 对象、函数等无法 JSON 序列化的内容
 */
function sanitizeForJSON(obj) {
  if (obj === null || obj === undefined) {
    return null;
  }

  if (typeof obj === 'string') {
    return obj;
  }

  if (typeof obj === 'number' || typeof obj === 'boolean') {
    return obj;
  }

  if (obj instanceof Error) {
    return `Error: ${obj.message}`;
  }

  if (typeof obj === 'function' || typeof obj === 'symbol') {
    return '[Unserializable]';
  }

  if (Array.isArray(obj)) {
    return obj.map((item) => sanitizeForJSON(item));
  }

  if (typeof obj === 'object') {
    // 检测并处理循环引用
    const seen = new WeakSet();
    const result = {};

    for (const [key, value] of Object.entries(obj)) {
      if (value === obj) continue; // 跳过自身引用
      if (seen.has(value)) {
        result[key] = '[Circular]';
        continue;
      }
      if (typeof value === 'object' && value !== null) {
        seen.add(value);
      }
      try {
        result[key] = sanitizeForJSON(value);
      } catch (e) {
        result[key] = '[Unserializable]';
      }
    }
    return result;
  }

  return String(obj);
}

/**
 * 清理工具结果内容，确保可安全序列化
 */
function sanitizeToolResult(result) {
  if (result === null || result === undefined) {
    return null;
  }

  // 如果已经是字符串，直接返回
  if (typeof result === 'string') {
    return result.substring(0, 50000); // 限制长度
  }

  // 如果是纯数据对象，直接序列化
  if (typeof result === 'number' || typeof result === 'boolean') {
    return result;
  }

  // 尝试安全序列化
  try {
    const sanitized = sanitizeForJSON(result);
    const str = JSON.stringify(sanitized);
    // 验证可以再次解析
    JSON.parse(str);
    return sanitized;
  } catch (e) {
    // 序列化失败，转换为字符串
    return String(result).substring(0, 50000);
  }
}

// 更激进的方法：确保所有消息都有有效的 content
// 接收 pairedIds 参数用于过滤未配对的 tool 消息
function validateAndFixMessages(messages, pairedIds = null) {
  return messages.filter((msg) => {
    // 如果提供了 pairedIds，检查 tool 消息是否配对
    if (pairedIds && msg.role === 'tool' && msg.toolCallId) {
      if (!pairedIds.has(msg.toolCallId)) {
        console.log(`丢弃消息: role=tool, toolCallId=${msg.toolCallId} 未配对`);
        return false;
      }
    }

    // 检查 content 是否存在且非空
    if (!msg.content) {
      console.log(`丢弃消息: role=${msg.role}, 无 content`);
      return false;
    }

    // 处理数组类型的 content
    if (Array.isArray(msg.content)) {
      if (msg.content.length === 0) {
        console.log(`丢弃消息: role=${msg.role}, content 为空数组`);
        return false;
      }

      // 检查数组中是否有有效内容
      const hasValidContent = msg.content.some((item) => {
        if (item.type === 'text' && item.text && item.text.trim()) {
          return true;
        }
        if (item.type === 'tool-call' && item.toolCallId) {
          return true;
        }
        if (item.type === 'tool-result' && item.toolCallId) {
          return true;
        }
        return false;
      });

      if (!hasValidContent) {
        console.log(`丢弃消息: role=${msg.role}, content 数组无有效内容`);
        return false;
      }
    }

    // 处理字符串类型的 content
    if (typeof msg.content === 'string' && !msg.content.trim()) {
      console.log(`丢弃消息: role=${msg.role}, content 为空字符串`);
      return false;
    }

    return true;
  });
}

// 完整处理流程
function prepareMessagesForAPI(rawMessages) {
  // 辅助函数：从消息中提取 toolCallId（兼容两种格式）
  // 格式1: msg.toolCallId (旧格式)
  // 格式2: msg.content[0].toolCallId (AI SDK CoreMessage 格式)
  function extractToolCallId(msg) {
    if (msg.toolCallId) return msg.toolCallId;
    if (Array.isArray(msg.content) && msg.content.length > 0) {
      const firstContent = msg.content[0];
      if (firstContent && firstContent.toolCallId) return firstContent.toolCallId;
    }
    return null;
  }

  // 1. 先配对，收集配对的 toolCallId
  const pairedIds = new Set();
  const toolCallToAssistant = new Map();
  const orphanedToolResults = []; // 用于调试：记录孤立的 tool results

  // 收集所有 assistant 的 tool-call
  for (let i = 0; i < rawMessages.length; i++) {
    const msg = rawMessages[i];
    if (msg.role === 'assistant' && msg.content) {
      const content = Array.isArray(msg.content) ? msg.content : [msg.content];
      for (const item of content) {
        if (item.type === 'tool-call' && item.toolCallId) {
          toolCallToAssistant.set(item.toolCallId, i);
        }
      }
    }
  }

  // 找出配对的 tool result（兼容两种格式）
  for (const msg of rawMessages) {
    if (msg.role === 'tool') {
      const toolCallId = extractToolCallId(msg);
      if (toolCallId && toolCallToAssistant.has(toolCallId)) {
        pairedIds.add(toolCallId);
      } else if (toolCallId) {
        // 记录孤立的 tool result（调试用）
        orphanedToolResults.push({
          toolCallId,
          hasAssistantMessage: toolCallToAssistant.has(toolCallId),
        });
      }
    }
  }

  // 调试：输出孤立 tool result 的信息（仅在有孤立结果时）
  if (orphanedToolResults.length > 0 && pairedIds.size > 0) {
    console.log(
      `[prepareMessagesForAPI] Warning: ${orphanedToolResults.length} orphaned tool results detected:`
    );
    for (const orphan of orphanedToolResults) {
      console.log(
        `  - toolCallId=${orphan.toolCallId}, hasAssistantMessage=${orphan.hasAssistantMessage}`
      );
    }
    console.log(`  Paired IDs: ${Array.from(pairedIds).join(', ')}`);
    console.log(`  Assistant tool-call IDs: ${Array.from(toolCallToAssistant.keys()).join(', ')}`);
  }

  // 2. 过滤并清理空消息，同时过滤未配对的 tool 消息
  const cleaned = [];
  for (const msg of rawMessages) {
    let shouldKeep = true;

    if (msg.role === 'assistant' && msg.content) {
      // 如果 content 是字符串（普通文本消息），保持不变
      if (typeof msg.content === 'string') {
        // 字符串内容不需要处理
      } else if (Array.isArray(msg.content)) {
        // content 是数组（包含 tool-call 等），进行过滤和清理
        // 过滤：保留有 tool result 的 tool-call，保留 text 类型
        const filteredContent = msg.content.filter((item) => {
          if (item.type === 'tool-call') {
            // 只保留有对应 tool result 的 tool call
            return pairedIds.has(item.toolCallId);
          }
          return true; // 保留 text 类型
        });

        // 检查过滤后是否还有有效内容
        if (filteredContent.length === 0) {
          shouldKeep = false;
        } else {
          // 清理 tool-result 内容项（assistant 消息中不应该有 tool-result，但以防万一）
          msg.content = filteredContent.map((item) => {
            if (item && item.type === 'tool-result' && item.result !== undefined) {
              return {
                ...item,
                result: sanitizeToolResult(item.result),
              };
            }
            return item;
          });
        }
      }
    }

    if (msg.role === 'tool') {
      // 检查 tool message 是否有配对的 tool call
      // 注意：一个 tool message 可能包含多个 tool-results，需要逐个检查
      if (Array.isArray(msg.content)) {
        // 过滤出有配对的 tool-results
        const pairedResults = msg.content.filter((item) => {
          if (item && item.type === 'tool-result' && item.toolCallId) {
            return pairedIds.has(item.toolCallId);
          }
          // 保留非 tool-result 类型的内容（如 text）
          return item && item.type !== 'tool-result';
        });

        // 检查是否有有效的 tool-results
        const hasPairedResults = pairedResults.some(
          (item) =>
            item && item.type === 'tool-result' && item.toolCallId && pairedIds.has(item.toolCallId)
        );

        if (!hasPairedResults) {
          // 所有 tool-results 都是orphaned，跳过整个消息
          console.log(
            `[prepareMessagesForAPI] Dropping tool message: all ${msg.content.length} tool-results are orphaned`
          );
          shouldKeep = false;
        } else {
          // 保留有配对的 tool-results，清理内容
          msg.content = pairedResults.map((item) => {
            if (item && item.type === 'tool-result' && item.result !== undefined) {
              return {
                ...item,
                result: sanitizeToolResult(item.result),
              };
            }
            return item;
          });
        }
      } else {
        // 非数组格式的 tool message（如旧格式）
        const toolCallId = extractToolCallId(msg);
        shouldKeep = toolCallId && pairedIds.has(toolCallId);
        if (shouldKeep && msg.content) {
          msg.content = sanitizeToolResult(msg.content);
        }
      }
    }

    // 验证 content 有效性
    if (shouldKeep) {
      if (!msg.content) {
        shouldKeep = false;
      } else if (Array.isArray(msg.content) && msg.content.length === 0) {
        shouldKeep = false;
      } else if (typeof msg.content === 'string' && !msg.content.trim()) {
        shouldKeep = false;
      }
    }

    if (shouldKeep) {
      cleaned.push(msg);
    }
  }

  // 3. 确保消息交替顺序正确（user/assistant/tool）
  const finalMessages = [];
  let lastRole = null;

  for (const msg of cleaned) {
    // 跳过连续的相同角色消息（除了 tool）
    if (msg.role === lastRole && msg.role !== 'tool') {
      continue;
    }

    finalMessages.push(msg);
    lastRole = msg.role;
  }

  return finalMessages;
}

// 发送给 API
// await yourAPI.call({ messages: cleanMessages });

module.exports = {
  // 日志
  Logger,
  logger,
  LOG_LEVELS,

  // ID 生成
  uuid,
  prefixedId,
  shortId,
  snowflake,
  taskId,
  goalId,
  sessionId,
  messageId,
  ruleId,
  resetSnowflake,

  // 错误处理
  FolikoError,
  PluginError,
  ToolError,
  AIError,
  SessionError,
  ConfigError,
  WorkflowError,
  ValidationError,
  ToolNotFoundError,
  PluginNotFoundError,
  isErrorOfType,
  safeErrorInfo,

  // 重试策略
  withRetry,
  retryable,
  isNetworkError,
  PRESETS,

  // 错误边界
  ErrorBoundary,
  Severity,
  RecoveryAction,
  createErrorBoundary,
  combineBoundaries,

  // 工具函数
  cleanResponse,
  safeJsonParse,
  deepClone,
  debounce,
  throttle,
  sleep,
  retry,
  prepareMessagesForAPI,
};
