/**
 * command-handler.js — 飞书斜杠命令处理
 *
 * 支持命令：
 *   /auth <token>        绑定 AgentHub 账号
 *   /unbind              解除绑定
 *   /new                 新建 Claude 会话
 *   /list                列出当前项目的会话
 *   /switch <id前缀>     切换到指定会话
 *   /project             查看当前状态
 *   /project list        列出项目
 *   /project create      创建新项目
 *   /project use <路径>  切换项目
 *   /mode                查看 / 选择权限模式
 *   /mode <name>         直接切换模式
 *   /stop                中止当前运行的会话
 *   /help                显示帮助
 *
 * 注意：messageId 可为 null（菜单点击事件没有原始消息），
 *       此时 _reply/_replyCard 自动降级为向 chatId 发新消息。
 */

import jwt from 'jsonwebtoken';
import { feishuDb } from './feishu-db.js';
import { PRODUCT_NAME, feishuBindingGuide } from '../../../shared/brand.js';
import { userDb } from '../../database/db.js';
import { abortClaudeSDKSession } from '../../claude-sdk.js';
import { getProjects, getSessions } from '../../projects.js';
import { JWT_SECRET } from '../../middleware/auth.js';
import {
  MODE_LABELS,
  MODEL_LABELS,
  stripProjectPrefix,
  buildModeSelectCardDirect,
  buildModelSelectCardDirect,
  buildStatusCardDirect,
  buildListCardDirect,
  buildDeleteListCardDirect,
  buildHelpCardDirect,
  buildCreateProjectCardDirect,
} from './card-builder.js';

const VALID_MODES = new Set(['default', 'acceptEdits', 'plan', 'bypassPermissions']);
const MODE_ALIASES = {
  edit:   'acceptEdits',
  yolo:   'bypassPermissions',
  bypass: 'bypassPermissions',
};

export class CommandHandler {
  constructor(larkClient) {
    this.larkClient = larkClient;
  }

  /**
   * 命令分发入口
   * @param {string} feishuOpenId
   * @param {string} chatId
   * @param {string|null} messageId   为 null 时（菜单事件）降级为发新消息
   * @param {string} rawText   原始消息文本（以 / 开头）
   * @returns {Promise<boolean>}  true = 命令已处理，false = 未识别
   */
  async dispatch(feishuOpenId, chatId, messageId, rawText) {
    const parts = rawText.trim().split(/\s+/);
    const cmd   = parts[0].toLowerCase();
    const args  = parts.slice(1);

    switch (cmd) {
      case '/auth':    return this._handleAuth(feishuOpenId, chatId, messageId, args[0]);
      case '/unbind':  return this._handleUnbind(feishuOpenId, chatId, messageId);
      case '/new':     return this._handleNew(feishuOpenId, chatId, messageId);
      case '/list':    return this._handleList(feishuOpenId, chatId, messageId);
      case '/switch':  return this._handleSwitch(feishuOpenId, chatId, messageId, args[0]);
      case '/project': return this._handleProject(feishuOpenId, chatId, messageId, args);
      case '/delete':  return this._handleDeleteSession(feishuOpenId, chatId, messageId);
      case '/mode':    return this._handleMode(feishuOpenId, chatId, messageId, args[0]);
      case '/model':   return this._handleModel(feishuOpenId, chatId, messageId, args[0]);
      case '/stop':    return this._handleStop(feishuOpenId, chatId, messageId);
      case '/help':    return this._handleHelp(feishuOpenId, chatId, messageId);
      default:
        await this._reply(chatId, messageId, `未知命令: \`${cmd}\`\n发送 /help 查看帮助`);
        return true;
    }
  }

  // ─── 命令实现 ────────────────────────────────────────────────────────────────

  async _handleAuth(feishuOpenId, chatId, messageId, token) {
    if (!token) {
      await this._reply(chatId, messageId,
        feishuBindingGuide()
      );
      return true;
    }

    let payload;
    try {
      payload = jwt.verify(token, JWT_SECRET);
    } catch {
      await this._reply(chatId, messageId, '❌ Token 无效或已过期，请重新生成。');
      return true;
    }

    const user = userDb.getUserByUuid?.(payload.uuid) || userDb.getUserById?.(payload.userId);
    if (!user || user.status === 'disabled') {
      await this._reply(chatId, messageId, '❌ 账号不存在或已被禁用。');
      return true;
    }

    feishuDb.createBinding(feishuOpenId, user.uuid);
    feishuDb.updateSessionState(feishuOpenId, {
      claude_session_id: null,
      cwd: '',
      permission_mode: 'default',
    });

    await this._reply(chatId, messageId,
      `✅ 绑定成功！欢迎 **${user.email || user.username}**\n\n发送 /help 查看可用命令。`
    );
    return true;
  }

  async _handleUnbind(feishuOpenId, chatId, messageId) {
    feishuDb.removeBinding(feishuOpenId);
    await this._reply(chatId, messageId, '✅ 已解除绑定。再次使用请重新发送 /auth <token>。');
    return true;
  }

  async _handleNew(feishuOpenId, chatId, messageId) {
    feishuDb.clearSession(feishuOpenId);
    const state = feishuDb.getSessionState(feishuOpenId) || {};

    const card = buildStatusCardDirect({ ...state, claude_session_id: null });
    await this._replyCard(chatId, messageId, card, 'interactive');
    return true;
  }

  async _handleList(feishuOpenId, chatId, messageId) {
    const binding = feishuDb.getBinding(feishuOpenId);
    if (!binding) {
      await this._reply(chatId, messageId, '请先发送 /auth <token> 完成账号绑定。');
      return true;
    }

    const state = feishuDb.getSessionState(feishuOpenId) || {};
    const cwd = state.cwd;

    if (!cwd) {
      await this._reply(chatId, messageId, '请先选择项目，发送 /project list 查看可用项目。');
      return true;
    }

    // 从项目路径提取项目名
    const projectName = _cwdToProjectName(cwd);

    let sessions = [];
    try {
      const result = await getSessions(projectName, 20, 0, binding.user_uuid);
      sessions = Array.isArray(result) ? result : (result?.sessions || []);
    } catch (err) {
      console.error('[Feishu:command] getSessions error:', err.message);
    }

    if (sessions.length === 0) {
      await this._reply(chatId, messageId, '当前项目暂无历史会话，直接发消息开始新会话。');
      return true;
    }

    const currentId = state.claude_session_id;
    const sliced = sessions.slice(0, 20);
    const items = sliced.map(s => {
      const isCurrent = s.id === currentId;
      const preview = (s.summary || s.lastUserMessage || '').slice(0, 40);
      return {
        label: `[${s.id?.slice(0, 8)}] ${preview}`,
        sub: isCurrent ? '◀ 当前会话' : '',
        isCurrent,
      };
    });

    this._storeSessionList(feishuOpenId, sliced);
    const card = buildListCardDirect({
      title: '💬 会话列表',
      items,
      actionType: 'session',
    });
    await this._replyCard(chatId, messageId, card, 'interactive');
    return true;
  }

  // 存储最近一次列表（供卡片回调使用）
  _listCache = new Map();

  _storeSessionList(feishuOpenId, sessions) {
    this._listCache.set(`${feishuOpenId}:sessions`, sessions);
    setTimeout(() => this._listCache.delete(`${feishuOpenId}:sessions`), 5 * 60 * 1000);
  }

  _storeProjectList(feishuOpenId, projects) {
    this._listCache.set(`${feishuOpenId}:projects`, projects);
    setTimeout(() => this._listCache.delete(`${feishuOpenId}:projects`), 5 * 60 * 1000);
  }

  getListCache(feishuOpenId, type) {
    return this._listCache.get(`${feishuOpenId}:${type}`) || [];
  }

  async _handleSwitch(feishuOpenId, chatId, messageId, arg) {
    if (!arg) {
      await this._reply(chatId, messageId, '用法：`/switch <序号或会话ID前缀>`');
      return true;
    }

    const binding = feishuDb.getBinding(feishuOpenId);
    if (!binding) { return this._requireAuth(chatId, messageId); }

    // 尝试按序号
    const index = parseInt(arg, 10);
    const sessions = this.getListCache(feishuOpenId, 'sessions');

    let targetSession = null;
    if (!isNaN(index) && index >= 1 && index <= sessions.length) {
      targetSession = sessions[index - 1];
    } else {
      // 按 ID 前缀匹配
      const prefix = arg.toLowerCase();
      targetSession = sessions.find(s => s.id?.toLowerCase().startsWith(prefix));
    }

    if (!targetSession) {
      await this._reply(chatId, messageId,
        `未找到会话 \`${arg}\`，请先发送 /list 查看列表。`
      );
      return true;
    }

    feishuDb.updateSessionState(feishuOpenId, { claude_session_id: targetSession.id });
    await this._reply(chatId, messageId,
      `✅ 已切换到会话 \`${targetSession.id?.slice(0, 8)}\``
    );
    return true;
  }

  async _handleProject(feishuOpenId, chatId, messageId, args) {
    const binding = feishuDb.getBinding(feishuOpenId);
    if (!binding) { return this._requireAuth(chatId, messageId); }

    const sub = args[0]?.toLowerCase();

    if (sub === 'delete') {
      let projects = [];
      try {
        projects = await getProjects(binding.user_uuid);
      } catch (err) {
        console.error('[Feishu:command] getProjects error:', err.message);
      }

      if (projects.length === 0) {
        await this._reply(chatId, messageId, '暂无项目可删除。');
        return true;
      }

      const state = feishuDb.getSessionState(feishuOpenId) || {};
      const currentCwd = state.cwd;
      const slicedProjects = projects.slice(0, 20);
      const items = slicedProjects.map(p => {
        const name = p.displayName || p.name;
        const sessions = p.sessionCount || p.sessions?.length || 0;
        const isCurrent = p.path === currentCwd || p.name === currentCwd;
        return {
          label: `${name} (${sessions} 个会话)`,
          sub: stripProjectPrefix(p.path || p.name),
          isCurrent,
        };
      });

      this._storeProjectList(feishuOpenId, slicedProjects);
      const card = buildDeleteListCardDirect({
        title: '🗑️ 删除项目',
        items,
        actionType: 'project',
      });
      await this._replyCard(chatId, messageId, card, 'interactive');
      return true;
    }

    if (sub === 'create') {
      const card = buildCreateProjectCardDirect();
      await this._replyCard(chatId, messageId, card, 'interactive');
      return true;
    }

    if (sub === 'list') {
      let projects = [];
      try {
        projects = await getProjects(binding.user_uuid);
      } catch (err) {
        console.error('[Feishu:command] getProjects error:', err.message);
      }

      if (projects.length === 0) {
        await this._reply(chatId, messageId, `暂无项目，请在 ${PRODUCT_NAME} 中创建项目。`);
        return true;
      }

      const slicedProjects = projects.slice(0, 20);
      const items = slicedProjects.map(p => {
        const name = p.displayName || p.name;
        const sessions = p.sessionCount || p.sessions?.length || 0;
        return {
          label: `${name} (${sessions} 个会话)`,
          sub: stripProjectPrefix(p.path || p.name),
        };
      });

      this._storeProjectList(feishuOpenId, slicedProjects);
      const card = buildListCardDirect({
        title: '📁 项目列表',
        items,
        actionType: 'project',
      });
      await this._replyCard(chatId, messageId, card, 'interactive');
      return true;
    }

    if (sub === 'use') {
      const arg = args.slice(1).join(' ').trim();
      if (!arg) {
        await this._reply(chatId, messageId, '用法：`/project use <序号或项目路径>`');
        return true;
      }

      let projectPath = arg;
      const index = parseInt(arg, 10);
      const projects = this.getListCache(feishuOpenId, 'projects');

      if (!isNaN(index) && index >= 1 && index <= projects.length) {
        projectPath = projects[index - 1].path || projects[index - 1].name;
      }

      feishuDb.updateSessionState(feishuOpenId, { cwd: projectPath, claude_session_id: null });
      const state = feishuDb.getSessionState(feishuOpenId) || {};

      const card = buildStatusCardDirect({ ...state, cwd: projectPath });
      await this._replyCard(chatId, messageId, card, 'interactive');
      return true;
    }

    // /project（无参数）→ 显示状态卡片
    const state = feishuDb.getSessionState(feishuOpenId) || {};
    const card = buildStatusCardDirect(state);
    await this._replyCard(chatId, messageId, card, 'interactive');
    return true;
  }

  async _handleMode(feishuOpenId, chatId, messageId, arg) {
    const binding = feishuDb.getBinding(feishuOpenId);
    if (!binding) { return this._requireAuth(chatId, messageId); }

    const state = feishuDb.getSessionState(feishuOpenId) || {};

    if (!arg) {
      // 无参数 → 显示模式选择卡片
      const card = buildModeSelectCardDirect(state.permission_mode || 'default');
      await this._replyCard(chatId, messageId, card, 'interactive');
      return true;
    }

    // 有参数 → 直接切换
    const normalizedMode = MODE_ALIASES[arg.toLowerCase()] || arg;
    if (!VALID_MODES.has(normalizedMode)) {
      await this._reply(chatId, messageId,
        `❌ 不支持的模式 \`${arg}\`\n可用：${[...VALID_MODES].join(', ')}`
      );
      return true;
    }

    feishuDb.updateSessionState(feishuOpenId, { permission_mode: normalizedMode });
    await this._reply(chatId, messageId,
      `✅ 已切换到 **${MODE_LABELS[normalizedMode]}** (\`${normalizedMode}\`)`
    );
    return true;
  }

  async _handleModel(feishuOpenId, chatId, messageId, arg) {
    const binding = feishuDb.getBinding(feishuOpenId);
    if (!binding) { return this._requireAuth(chatId, messageId); }

    const state = feishuDb.getSessionState(feishuOpenId) || {};

    if (!arg) {
      const card = buildModelSelectCardDirect(state.claude_model || 'sonnet');
      await this._replyCard(chatId, messageId, card, 'interactive');
      return true;
    }

    const VALID_MODELS = new Set(['sonnet', 'opus', 'haiku']);
    if (!VALID_MODELS.has(arg)) {
      await this._reply(chatId, messageId,
        `❌ 不支持的模型 \`${arg}\`\n可用：${[...VALID_MODELS].join(', ')}`
      );
      return true;
    }

    feishuDb.updateSessionState(feishuOpenId, { claude_model: arg });
    await this._reply(chatId, messageId,
      `✅ 已切换到 **${MODEL_LABELS[arg]}** (\`${arg}\`)`
    );
    return true;
  }

  async _handleDeleteSession(feishuOpenId, chatId, messageId) {
    const binding = feishuDb.getBinding(feishuOpenId);
    if (!binding) { return this._requireAuth(chatId, messageId); }

    const state = feishuDb.getSessionState(feishuOpenId) || {};
    const cwd = state.cwd;

    if (!cwd) {
      await this._reply(chatId, messageId, '请先选择项目，发送 /project list 查看可用项目。');
      return true;
    }

    const projectName = _cwdToProjectName(cwd);

    let sessions = [];
    try {
      const result = await getSessions(projectName, 20, 0, binding.user_uuid);
      sessions = Array.isArray(result) ? result : (result?.sessions || []);
    } catch (err) {
      console.error('[Feishu:command] getSessions error:', err.message);
    }

    if (sessions.length === 0) {
      await this._reply(chatId, messageId, '当前项目暂无历史会话。');
      return true;
    }

    const currentId = state.claude_session_id;
    const sliced = sessions.slice(0, 20);
    const items = sliced.map(s => {
      const isCurrent = s.id === currentId;
      const preview = (s.summary || s.lastUserMessage || '').slice(0, 40);
      return {
        label: `[${s.id?.slice(0, 8)}] ${preview}`,
        sub: isCurrent ? '◀ 当前会话' : '',
        isCurrent,
      };
    });

    this._storeSessionList(feishuOpenId, sliced);
    const card = buildDeleteListCardDirect({
      title: '🗑️ 删除会话',
      items,
      actionType: 'session',
    });
    await this._replyCard(chatId, messageId, card, 'interactive');
    return true;
  }

  async _handleStop(feishuOpenId, chatId, messageId) {
    const state = feishuDb.getSessionState(feishuOpenId);
    const sessionId = state?.claude_session_id;
    if (sessionId) {
      const ok = await abortClaudeSDKSession(sessionId);
      await this._reply(chatId, messageId, ok ? '✅ 已中止当前会话' : '当前无正在运行的会话');
    } else {
      await this._reply(chatId, messageId, '当前无活跃会话。');
    }
    return true;
  }

  async _handleHelp(feishuOpenId, chatId, messageId) {
    const binding = feishuDb.getBinding(feishuOpenId);
    const user = binding ? (userDb.getUserByUuid?.(binding.user_uuid) || null) : null;
    const email = user?.email || user?.username || '未绑定';
    const state = feishuDb.getSessionState(feishuOpenId);

    await this._replyCard(chatId, messageId, buildHelpCardDirect(email, state), 'interactive');
    return true;
  }

  // ─── 工具方法 ─────────────────────────────────────────────────────────────────

  /**
   * 有 messageId 则回复原消息（线程化），否则向 chatId 发新消息。
   * 自动检测 chatId 类型：
   *   - 以 "oc_" 开头 → p2p chat_id，用 sendText（receive_id_type: chat_id）
   *   - 以 "ou_" 开头 → open_id，用 sendTextToUser（receive_id_type: open_id）
   */
  async _reply(chatId, messageId, text) {
    if (messageId) return this.larkClient.replyText(messageId, text);
    if (!chatId) { console.warn('[Feishu:command] _reply: no messageId and no chatId'); return; }
    if (chatId.startsWith('ou_')) return this.larkClient.sendTextToUser(chatId, text);
    return this.larkClient.sendText(chatId, text);
  }

  /**
   * 有 messageId 则回复原消息（线程化），否则向 chatId 发新卡片消息。
   * 同样自动检测 chatId 类型（oc_ vs ou_）。
   */
  async _replyCard(chatId, messageId, card, msgType = 'interactive') {
    if (messageId) return this.larkClient.replyMessage(messageId, card, msgType);
    if (!chatId) { console.warn('[Feishu:command] _replyCard: no messageId and no chatId'); return; }
    if (chatId.startsWith('ou_')) return this.larkClient.sendMessageToUser(chatId, card, msgType);
    return this.larkClient.sendMessage(chatId, card, msgType);
  }

  async _requireAuth(chatId, messageId) {
    await this._reply(chatId, messageId, '请先发送 /auth <token> 完成账号绑定。');
    return true;
  }
}

// 从 cwd 路径推断项目名（Claude projects 目录中的 hash 编码路径名）
// projects 目录结构: ~/.agenthub/users/<UUID>/.claude/projects/<projectName>/
// projectName 是对实际路径的编码：将 '/' 替换为 '-'
function _cwdToProjectName(cwd) {
  if (!cwd) return '';
  // Claude CLI 的编码规则：将路径中所有 '/' 替换为 '-'
  // 例如 /Users/user/myproject → -Users-user-myproject
  return cwd.replace(/\//g, '-');
}
