/**
 * sdk-bridge.js — FakeSendWriter + queryClaudeSDK 调用适配
 *
 * FakeSendWriter 实现与 WebSocketWriter 相同的 .send(data) / .setSessionId(id) 接口，
 * 使得 queryClaudeSDK 可以直接复用，无需修改 claude-sdk.js。
 *
 * 消息路由策略：
 *   - claude-response(text)    → 累积到 textBuffer，完成时统一发送
 *   - claude-response(other)   → 工具调用等，发简短通知
 *   - claude-permission-request → 发工具审批卡片，挂起 Promise
 *   - claude-permission-cancelled → 更新卡片为已取消
 *   - session-created          → 保存 sessionId
 *   - claude-complete          → 发送聚合响应，保存 sessionId 到 DB
 *   - token-budget             → 忽略（统计不准确，不推送给用户）
 *   - claude-error             → 发送错误提示
 */

import { queryClaudeSDK } from '../../claude-sdk.js';
import { usageDb, userDb } from '../../database/db.js';
import { feishuDb } from './feishu-db.js';
import fs from 'fs/promises';
import path from 'path';
import {
  buildToolApprovalCardDirect,
  buildToolApprovalResultCardDirect,
  buildAskUserQuestionCard,
  splitMessage,
  truncate,
} from './card-builder.js';

// ─── 飞书模式系统提示词 ─────────────────────────────────────────────────────────
// 追加到 claude_code preset 之后，让 Claude 感知飞书环境和文件发送能力
const FEISHU_SYSTEM_PROMPT = `
你正在通过飞书（Lark）消息与用户进行对话（飞书 IM 模式）。

文件发送能力：
- 你通过 Write 工具创建的图片（png/jpg/jpeg/gif/webp/bmp）和文档文件（pdf/docx/xlsx/pptx/zip/tar.gz/svg 等），会在回复结束后自动作为飞书附件发送给用户，无需声称自己无法发送文件。
- 如需将项目中已存在的文件发送给用户，在回复中添加 [[FEISHU_SEND_FILE::<文件绝对路径>]] 标签（支持多个），系统会自动读取并发送该文件，该标签不会显示给用户。

示例（发送已有文件）：
[[FEISHU_SEND_FILE::/Users/xxx/project/output.zip]]
好的，已将 output.zip 发送给你。
`.trim();

class FakeSendWriter {
  /**
   * @param {Object} opts
   * @param {string} opts.feishuOpenId
   * @param {string} opts.chatId
   * @param {string} opts.replyMessageId  原始用户消息 ID（用于回复线程化）
   * @param {Object} opts.larkClient      LarkClient 实例
   * @param {Map}    opts.pendingApprovals engine 的挂起审批 Map
   */
  constructor({ feishuOpenId, chatId, replyMessageId, larkClient, pendingApprovals, cwd }) {
    this.feishuOpenId     = feishuOpenId;
    this.chatId           = chatId;
    this.replyMessageId   = replyMessageId;
    this.larkClient       = larkClient;
    this.pendingApprovals = pendingApprovals;
    this.cwd              = cwd;

    this.textBuffer       = [];     // 累积 claude-response text 内容
    this.sessionId        = null;   // 从 session-created 或 claude-response.session_id 获取
    this.toolNotices      = [];     // 工具调用通知（可选展示）
    this.sessionCorrupted = false;  // 会话历史包含空 text block，需重置
    this.writtenFiles     = [];     // Write 工具写入的文件路径（用于完成后发送）
  }

  // ─── WebSocketWriter 接口 ──────────────────────────────────────────────────

  send(data) {
    console.log('[Feishu:sdk-bridge] send() type:', data?.type, data?.type === 'claude-response' ? `msg.type=${data?.data?.type}` : '');
    try {
      this._handle(data);
    } catch (err) {
      console.error('[Feishu:sdk-bridge] FakeSendWriter.send error:', err.message);
    }
  }

  setSessionId(id) {
    this.sessionId = id;
  }

  getSessionId() {
    return this.sessionId;
  }

  /** 优先用 chat_id，回退到 feishuOpenId（open_id），LarkClient 会自动识别类型 */
  get _target() {
    return this.chatId || this.feishuOpenId;
  }

  // ─── 消息路由 ──────────────────────────────────────────────────────────────

  _handle(data) {
    switch (data.type) {
      case 'claude-response':
        this._handleResponse(data.data);
        break;

      case 'claude-permission-request':
        this._handlePermissionRequest(data).catch(err =>
          console.error('[Feishu:sdk-bridge] permission request send error:', err.message)
        );
        break;

      case 'claude-permission-cancelled':
        this._handlePermissionCancelled(data).catch(() => {});
        break;

      case 'session-created':
        if (data.sessionId && !this.sessionId) {
          this.sessionId = data.sessionId;
        }
        break;

      case 'claude-complete':
        this._handleComplete(data).catch(err =>
          console.error('[Feishu:sdk-bridge] complete handler error:', err.message)
        );
        break;

      case 'token-budget':
        this._handleTokenBudget(data.data);
        break;

      case 'claude-error':
        this._handleError(data.error).catch(() => {});
        break;

      default:
        // 其他类型（session-aborted 等）忽略
        break;
    }
  }

  _handleResponse(msg) {
    if (!msg) return;

    // 捕获 session_id
    if (msg.session_id && !this.sessionId) {
      this.sessionId = msg.session_id;
    }

    switch (msg.type) {
      // SDK 标准格式：完整 assistant 消息，content 数组包含 text/tool_use 块
      case 'assistant': {
        const blocks = msg.message?.content || [];
        for (const block of blocks) {
          if (block.type === 'text' && block.text) {
            this.textBuffer.push(block.text);
          } else if (block.type === 'tool_use' && block.name) {
            this.toolNotices.push(`🔧 调用 \`${block.name}\``);
            this.larkClient.sendTextToTarget(this._target, `🔧 正在调用 \`${block.name}\`…`).catch(() => {});
            // 追踪 Write 工具写入的文件路径，完成后按类型发送给用户
            if (block.name === 'Write' && block.input?.file_path) {
              this.writtenFiles.push(block.input.file_path);
            }
          }
        }
        break;
      }

      // 兼容：流式增量格式
      case 'content_block_delta':
        if (msg.delta?.text) this.textBuffer.push(msg.delta.text);
        break;

      // 兼容：流式块开始（工具调用）
      case 'content_block_start': {
        const block = msg.content_block;
        if (block?.type === 'tool_use' && block.name) {
          this.toolNotices.push(`🔧 调用 \`${block.name}\``);
          this.larkClient.sendTextToTarget(this._target, `🔧 正在调用 \`${block.name}\`…`).catch(() => {});
        }
        break;
      }

      // 兼容：旧版 text 格式
      case 'text':
        if (msg.text) this.textBuffer.push(msg.text);
        break;

      // 兼容：旧版 tool_use 格式
      case 'tool_use':
        if (msg.name) {
          this.toolNotices.push(`🔧 调用 \`${msg.name}\``);
          this.larkClient.sendTextToTarget(this._target, `🔧 正在调用 \`${msg.name}\`…`).catch(() => {});
        }
        break;

      case 'system':
      case 'thinking':
      case 'content_block_stop':
      case 'message_start':
      case 'message_delta':
      case 'message_stop':
        // 不推送
        break;

      case 'result':
        // 检测会话历史损坏（空 text block 导致 Anthropic API 400 错误）
        if (msg.is_error && typeof msg.result === 'string' &&
            msg.result.includes('text content blocks must be non-empty')) {
          this.sessionCorrupted = true;
        }
        break;

      default:
        console.log('[Feishu:sdk-bridge] _handleResponse unknown msg.type:', msg.type);
        break;
    }
  }

  async _handlePermissionRequest(data) {
    const { requestId, toolName, input } = data;
    if (!requestId) return;

    // AskUserQuestion：展示问卷，等待用户回复选项
    if (toolName === 'AskUserQuestion') {
      await this._handleAskUserQuestion(requestId, input);
      return;
    }

    // 直接发送交互卡片（JSON 构建，无需模板 ID）
    const cardContent = buildToolApprovalCardDirect(toolName, input, requestId);
    const cardMsgId = await this.larkClient.sendInteractiveAndGetMsgId(this._target, cardContent).catch(async () => {
      const inputSummary = truncate(
        typeof input === 'object' ? JSON.stringify(input, null, 2) : String(input || ''),
        300
      );
      const text = `🔔 **工具审批请求**\n工具: \`${toolName}\`\n参数:\n\`\`\`\n${inputSummary}\n\`\`\`\n\n回复 **允许** 或 **拒绝**（或 **允许所有** 跳过同类工具询问）`;
      await this.larkClient.sendTextToTarget(this._target, text).catch(() => {});
      return null;
    });
    this.pendingApprovals.set(this.feishuOpenId, { requestId, cardMessageId: cardMsgId, toolName });
  }

  async _handleAskUserQuestion(requestId, input) {
    const questions = input?.questions || [];

    // 发送交互卡片（动态 JSON，无需模板 ID）
    const cardContent = buildAskUserQuestionCard(questions, requestId);
    const cardMsgId = await this.larkClient.sendInteractiveAndGetMsgId(this._target, cardContent)
      .catch(async (err) => {
        console.error('[Feishu:sdk-bridge] AskUserQuestion card send error:', err.message);
        // 降级：发送文字说明，用户通过文字回复选项字母
        const LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        const lines = ['🤔 **Claude 需要您的回答**\n'];
        questions.forEach((q, qi) => {
          const multiNote = q.multiSelect ? ' 〔可多选〕' : '';
          lines.push(`**${qi + 1}. ${q.question}**${multiNote}`);
          (q.options || []).forEach((opt, oi) => {
            const letter = LETTERS[oi] || String(oi + 1);
            lines.push(`   ${letter}. ${opt.label}${opt.description ? ` — ${opt.description}` : ''}`);
          });
          lines.push('');
        });
        lines.push(questions.length > 1
          ? '回复格式：各题选项字母用逗号分隔，多选用 + 连接（如 A,A+B,B）'
          : '回复选项字母（多选用 + 连接，如 A+B）'
        );
        lines.push('回复"跳过"可跳过此问卷。');
        await this.larkClient.sendTextToTarget(this._target, lines.join('\n')).catch(() => {});
        return null;
      });

    this.pendingApprovals.set(this.feishuOpenId, {
      requestId,
      cardMessageId: cardMsgId,
      toolName: 'AskUserQuestion',
      questions,
      originalInput: input,
    });
  }

  async _handlePermissionCancelled(data) {
    const pending = this.pendingApprovals.get(this.feishuOpenId);
    if (!pending) return;

    if (pending.cardMessageId) {
      const updatedCard = buildToolApprovalResultCardDirect('timeout');
      await this.larkClient.updateCard(pending.cardMessageId, updatedCard).catch(() => {});
    }
    this.pendingApprovals.delete(this.feishuOpenId);
  }

  async _handleComplete(data) {
    // 持久化 session ID
    if (this.sessionId) {
      feishuDb.updateSessionState(this.feishuOpenId, { claude_session_id: this.sessionId });
    }

    // 提取并移除文本中的 [[FEISHU_SEND_FILE::...]] 标签，收集待发送的已有文件路径
    const taggedFiles = [];
    const rawText = this.textBuffer.join('');
    const cleanedText = rawText
      .replace(/\[\[FEISHU_SEND_FILE::([^\]]+)\]\]/g, (_, filePath) => {
        taggedFiles.push(filePath.trim());
        return '';
      })
      .trim();

    // 发送聚合后的文本响应
    console.log(`[Feishu:sdk-bridge] _handleComplete: textBuffer.length=${this.textBuffer.length}, cleanedText.length=${cleanedText.length}, chatId=${this.chatId}`);
    if (cleanedText) {
      const chunks = splitMessage(cleanedText, 4000);
      for (const chunk of chunks) {
        try {
          await this.larkClient.sendTextToTarget(this._target, chunk);
          console.log('[Feishu:sdk-bridge] sendText OK, chunk.length=', chunk.length);
        } catch (err) {
          console.error('[Feishu:sdk-bridge] sendText FAILED:', err.message, err.stack);
        }
      }
    } else {
      console.warn('[Feishu:sdk-bridge] _handleComplete: cleanedText is empty, nothing sent to Feishu');
    }

    // 发送 Write 工具写入的图片 / 文档类文件
    await this._sendWrittenFiles();
    // 发送 [[FEISHU_SEND_FILE::...]] 标签指定的已有文件
    await this._sendTaggedFiles(taggedFiles);

    this.textBuffer = [];
  }

  // 图片扩展名 → 用 sendImageBuffer 发送
  static IMAGE_EXTS = new Set(['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp']);
  // 文档/归档扩展名 → 用 sendFileBuffer 发送
  static FILE_EXTS  = new Set(['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'zip', 'tar', 'gz', 'svg']);

  async _sendWrittenFiles() {
    if (!this.writtenFiles.length) return;
    const uniquePaths = [...new Set(this.writtenFiles)];
    this.writtenFiles = [];

    for (const filePath of uniquePaths) {
      const resolved = path.isAbsolute(filePath)
        ? filePath
        : path.join(this.cwd || process.cwd(), filePath);
      const ext      = path.extname(resolved).toLowerCase().slice(1);
      const filename = path.basename(resolved);

      if (!FakeSendWriter.IMAGE_EXTS.has(ext) && !FakeSendWriter.FILE_EXTS.has(ext)) continue;

      try {
        const buf = await fs.readFile(resolved);
        if (FakeSendWriter.IMAGE_EXTS.has(ext)) {
          await this.larkClient.sendImageBuffer(this._target, buf);
          console.log(`[Feishu:sdk-bridge] Sent image: ${filename}`);
        } else {
          await this.larkClient.sendFileBuffer(this._target, buf, filename);
          console.log(`[Feishu:sdk-bridge] Sent file: ${filename}`);
        }
      } catch (err) {
        console.warn(`[Feishu:sdk-bridge] Failed to send written file ${resolved}:`, err.message);
      }
    }
  }

  async _sendTaggedFiles(filePaths) {
    if (!filePaths.length) return;
    for (const filePath of filePaths) {
      const ext      = path.extname(filePath).toLowerCase().slice(1);
      const filename = path.basename(filePath);
      try {
        const buf = await fs.readFile(filePath);
        if (FakeSendWriter.IMAGE_EXTS.has(ext)) {
          await this.larkClient.sendImageBuffer(this._target, buf);
          console.log(`[Feishu:sdk-bridge] Sent tagged image: ${filename}`);
        } else {
          await this.larkClient.sendFileBuffer(this._target, buf, filename);
          console.log(`[Feishu:sdk-bridge] Sent tagged file: ${filename}`);
        }
      } catch (err) {
        console.warn(`[Feishu:sdk-bridge] Failed to send tagged file ${filePath}:`, err.message);
      }
    }
  }

  _handleTokenBudget(budget) {
    // token-budget 提醒统计不准确，不向用户推送
  }

  async _handleError(errorMsg) {
    // 会话损坏时不发通用错误（由 runQuery 统一处理并重置会话）
    if (this.sessionCorrupted) return;
    await this.larkClient.sendTextToTarget(this._target, `❌ 出错了：${errorMsg || '未知错误'}`).catch(() => {});
  }
}

// ─── runQuery — 统一入口 ────────────────────────────────────────────────────────

/**
 * 调用 Claude SDK 并将结果通过 FakeSendWriter 发送到飞书
 *
 * @param {Object} opts
 * @param {string} opts.feishuOpenId
 * @param {string} opts.chatId
 * @param {string} opts.messageId          原始消息 ID
 * @param {string} opts.content            用户输入文字
 * @param {Array|null} opts.images         图片附件（已转换为 data URI 格式）
 * @param {string} opts.userUuid           agenthub 用户 UUID
 * @param {Object} opts.state              feishu_session_state 行
 * @param {Object} opts.larkClient         LarkClient 实例
 * @param {Map}    opts.pendingApprovals   engine 共享的 pendingApprovals Map
 */
async function runQuery({
  feishuOpenId,
  chatId,
  messageId,
  content,
  images,
  userUuid,
  state,
  larkClient,
  pendingApprovals,
}) {
  // 限额检查（super_admin 豁免）
  const feishuUser = userDb.getUserByUuid(userUuid);
  if (feishuUser?.role !== 'super_admin') {
    const limitStatus = usageDb.checkUserLimits(userUuid);
    if (!limitStatus.allowed) {
      const reason = limitStatus.reason === 'daily_limit_exceeded'
        ? `每日用量已达上限 ($${limitStatus.limit.toFixed(2)})`
        : `总用量已达上限 ($${limitStatus.limit.toFixed(2)})`;
      await larkClient.sendTextToTarget(chatId || feishuOpenId, `⚠️ ${reason}，请联系管理员。`);
      return;
    }
  }

  const { claude_session_id, cwd, permission_mode, claude_model } = state || {};

  const writer = new FakeSendWriter({
    feishuOpenId,
    chatId,
    replyMessageId: messageId,
    larkClient,
    pendingApprovals,
    cwd: cwd || undefined,
  });

  // 图片：LarkClient 已将二进制转为 {data: Buffer, mimeType} 格式
  // queryClaudeSDK 的 handleImages 期望 data URI 格式
  const imageOptions = images?.map(img => ({
    data: `data:${img.mimeType};base64,${img.data.toString('base64')}`,
  })) || undefined;

  try {
    await queryClaudeSDK(content, {
      sessionId:          claude_session_id || undefined,
      userUuid,
      cwd:                cwd || undefined,
      permissionMode:     permission_mode || 'default',
      model:              claude_model || undefined,
      images:             imageOptions,
      toolsSettings:      { allowedTools: [], disallowedTools: [], skipPermissions: false },
      appendSystemPrompt: FEISHU_SYSTEM_PROMPT,
    }, writer);
  } catch (err) {
    // queryClaudeSDK 内部已经通过 writer 发送错误，这里仅记录日志
    console.error('[Feishu:sdk-bridge] queryClaudeSDK error:', err.message);
  }

  // 会话历史损坏（空 text block）：自动清除坏会话，提示用户重发
  if (writer.sessionCorrupted) {
    feishuDb.updateSessionState(feishuOpenId, { claude_session_id: null });
    await larkClient.sendTextToTarget(chatId || feishuOpenId,
      '⚠️ 检测到历史会话数据异常，已自动重置会话。请重新发送消息，将以新会话继续。'
    ).catch(() => {});
  }
}

export { FakeSendWriter, runQuery };
