import crypto from 'crypto';
import cron from 'node-cron';
import { cronScheduler } from './cron-scheduler.js';
import { feishuDb } from '../../database/db.js';

const MAX_PER_USER = 10;

/**
 * 剥离参数字符串两端的引号（支持直引号和 curly quotes）并解析 JSON
 * 同时将 AI 错误写入的 \' 还原为单引号（\' 在 JSON 中非法，但单引号本身在 JSON 字符串值里合法）
 */
function parseJsonArg(raw) {
  let s = raw.trim();
  // 直引号 ' " 和 curly quotes \u2018\u2019\u201C\u201D
  s = s.replace(/^[\s\u2018\u201C'"]|[\s\u2019\u201D'"]+$/g, '').trim();
  // 修复 AI 错误转义：\' → '（JSON 不支持 \'，但单引号本身合法）
  s = s.replace(/\\'/g, "'");
  return JSON.parse(s);
}

/**
 * 解析 prompt 开头的 [session:...] 和 [channel:...] 前缀（双前缀，任意顺序，均可选）
 * 返回 { sessionMode, channel, webhookUrl, prompt }
 */
function parsePrefixes(rawPrompt, defaults) {
  let s = rawPrompt;
  let sessionMode = defaults.sessionMode;
  let channel = defaults.channel;
  let webhookUrl = null;

  let changed = true;
  while (changed) {
    changed = false;

    const sm = s.match(/^\[session:(new_session|resume_session)\]/);
    if (sm) {
      sessionMode = sm[1];
      s = s.slice(sm[0].length).trimStart();
      changed = true;
    }

    const ch = s.match(/^\[channel:([^\]]*)\]/);
    if (ch) {
      const spec = ch[1];
      if (spec.startsWith('webhook:')) {
        channel = 'webhook';
        webhookUrl = spec.slice(8);
      } else {
        channel = spec;
      }
      s = s.slice(ch[0].length).trimStart();
      changed = true;
    }
  }

  return { sessionMode, channel, webhookUrl, prompt: s };
}

/**
 * 等待 mutableWriter 中的 sessionId 被赋值（最多 5s）
 */
async function waitForSessionId(mutableWriter) {
  let sessionId = mutableWriter?.current?.getSessionId?.();
  if (sessionId) return sessionId;
  return new Promise((resolve) => {
    const interval = setInterval(() => {
      const sid = mutableWriter?.current?.getSessionId?.();
      if (sid) { clearInterval(interval); resolve(sid); }
    }, 200);
    setTimeout(() => { clearInterval(interval); resolve(null); }, 5000);
  });
}

// ─── __cron_create__ ──────────────────────────────────────────────────────────

export const cronCreateTool = {
  name: '__cron_create__',

  systemPrompt: `
## 定时任务（Cron）
使用以下 Bash 命令操作定时任务（任务持久化到数据库，服务重启自动恢复，循环任务永久运行直到用户手动删除）：

### 创建定时任务
\`\`\`
Bash(__cron_create__ '{"cron":"0 9 * * 1-5","prompt":"分析昨日 git 提交","recurring":true}')
\`\`\`

参数说明：
- cron: 标准 5 字段 cron 表达式（如 "*/5 * * * *"）
- prompt: 触发时执行的内容，开头可加前缀指定会话方式和投递渠道
- recurring: true=循环（永久），false=单次（触发后删除）

### 前缀说明（**创建前务必询问用户**，在 prompt 开头使用，顺序任意，均可选）：

**会话方式**（决定使用哪个 Claude 会话上下文）：
- [session:new_session]（默认）：每次触发创建全新会话（隔离，适合独立任务）
- [session:resume_session]：每次触发 resume 创建任务时的会话（连续性，适合长期跟踪）

**投递渠道**（决定结果发往哪里）：
- （无前缀，网页端默认）：服务端执行，结果存入会话历史，用户登录后可查看
- [channel:feishu]（飞书端默认）：直接向绑定的飞书会话发送结果
- [channel:webhook:https://...]：将 Claude 回复 POST 到指定 URL

两种前缀可自由组合，例如：
- [session:resume_session]每日代码审查
- [channel:webhook:https://hooks.example.com/][session:resume_session]汇报项目进展

所有执行均在服务端完成，不依赖用户是否在线。每用户最多 ${MAX_PER_USER} 个并发任务。

### 删除定时任务
\`\`\`
Bash(__cron_delete__ '{"id":"任务ID"}')
\`\`\`

### 查看定时任务列表
\`\`\`
Bash(__cron_list__)
\`\`\`
`,

  match(hookInput) {
    return hookInput.tool_name === 'Bash' &&
      hookInput.tool_input?.command?.trimStart().startsWith('__cron_create__');
  },

  async execute(hookInput, ctx) {
    const rawArgs = hookInput.tool_input.command.replace(/^\s*__cron_create__\s*/, '');
    let params;
    try {
      params = parseJsonArg(rawArgs);
    } catch (e) {
      return { decision: 'deny', reason: `参数解析失败: ${e.message}。请使用 JSON 格式：__cron_create__ '{"cron":"...","prompt":"...","recurring":true}'` };
    }

    const { cron: cronExpr, prompt: rawPrompt, recurring = true } = params;
    const { userUuid, mutableWriter, cwd } = ctx;

    if (!cronExpr || !rawPrompt) {
      return { decision: 'deny', reason: '❌ 缺少必要参数 cron 或 prompt' };
    }

    if (!cron.validate(cronExpr)) {
      return { decision: 'deny', reason: `❌ 无效的 cron 表达式: ${cronExpr}（需要标准 5 字段格式，如 "*/5 * * * *"）` };
    }

    // 检测渠道（飞书 vs 网页），确定默认值
    const feishuOpenId = mutableWriter?.current?.feishuOpenId || null;
    const chatId       = mutableWriter?.current?.chatId || null;
    const defaults = feishuOpenId
      ? { sessionMode: 'new_session', channel: 'feishu' }
      : { sessionMode: 'new_session', channel: '' };

    // 解析投递前缀
    const { sessionMode, channel, webhookUrl, prompt } = parsePrefixes(rawPrompt, defaults);

    // webhook 模式需要有效 URL
    if (channel === 'webhook' && !webhookUrl) {
      return { decision: 'deny', reason: '❌ webhook 渠道需要指定 URL，格式: [channel:webhook:https://...]' };
    }

    // feishu 模式需要用户已绑定飞书账号
    if (channel === 'feishu') {
      const binding = feishuDb.getBindingByUserUuid(userUuid);
      if (!binding) {
        return { decision: 'deny', reason: '❌ 当前账号未绑定飞书，无法使用飞书投递渠道。请先在设置 > 账户中绑定飞书账号，或选择其他投递渠道。' };
      }
    }

    // 等待 sessionId（最多 5s，resume_session 模式下需要）
    const sessionId = await waitForSessionId(mutableWriter);

    const id = crypto.randomUUID().slice(0, 8);
    try {
      cronScheduler.create({
        id, cronExpr, prompt, recurring,
        userUuid, sessionId,
        projectPath: cwd || null,
        sessionMode, channel,
        feishuOpenId, chatId,
        webhookUrl: webhookUrl || null,
      });
    } catch (err) {
      return { decision: 'deny', reason: `❌ 创建失败：${err.message}` };
    }

    const channelDesc = {
      '': '服务端执行（存入会话历史）',
      'feishu': '飞书直投',
      'webhook': `Webhook POST → ${webhookUrl}`,
    }[channel] ?? channel;

    const sessionDesc = {
      'new_session': '新建会话',
      'resume_session': 'Resume 原会话',
    }[sessionMode] ?? sessionMode;

    return {
      decision: 'deny',
      reason: [
        `✅ 定时任务已创建并持久化`,
        `任务 ID: ${id}`,
        `频率: ${cronExpr}`,
        `类型: ${recurring ? '循环（永久）' : '单次'}`,
        `会话方式: ${sessionDesc}`,
        `投递渠道: ${channelDesc}`,
        `内容: ${prompt}`,
      ].join('\n'),
    };
  },
};

// ─── __cron_delete__ ──────────────────────────────────────────────────────────

export const cronDeleteTool = {
  name: '__cron_delete__',

  systemPrompt: '',

  match(hookInput) {
    return hookInput.tool_name === 'Bash' &&
      hookInput.tool_input?.command?.trimStart().startsWith('__cron_delete__');
  },

  async execute(hookInput, ctx) {
    const rawArgs = hookInput.tool_input.command.replace(/^\s*__cron_delete__\s*/, '');
    let params;
    try {
      params = parseJsonArg(rawArgs);
    } catch (e) {
      return { decision: 'deny', reason: `参数解析失败: ${e.message}。请使用 JSON 格式：__cron_delete__ '{"id":"任务ID"}'` };
    }

    const { id } = params;
    if (!id) return { decision: 'deny', reason: '❌ 缺少任务 ID' };
    const ok = cronScheduler.delete(id, ctx.userUuid);
    return {
      decision: 'deny',
      reason: ok
        ? `✅ 定时任务 ${id} 已取消并从数据库删除`
        : `❌ 任务 ${id} 不存在或无权限删除（当前用户 UUID: ${ctx.userUuid}）`,
    };
  },
};

// ─── __cron_list__ ────────────────────────────────────────────────────────────

export const cronListTool = {
  name: '__cron_list__',

  systemPrompt: '',

  match(hookInput) {
    return hookInput.tool_name === 'Bash' &&
      hookInput.tool_input?.command?.trimStart().startsWith('__cron_list__');
  },

  async execute(_hookInput, ctx) {
    const tasks = cronScheduler.list(ctx.userUuid);
    if (!tasks.length) {
      return { decision: 'deny', reason: `No scheduled jobs for user ${ctx.userUuid}.` };
    }
    const lines = tasks.map(t => {
      const channelInfo = t.channel === 'webhook' ? ` webhook=${t.webhookUrl}` :
                          t.channel ? ` channel=${t.channel}` : '';
      const fired = t.lastFiredAt ? ` last_fired=${new Date(t.lastFiredAt).toISOString()}` : '';
      return `ID: ${t.id}  cron: ${t.cronExpr}  ${t.recurring ? 'recurring' : 'once'}  session: ${t.sessionMode || 'new_session'}  channel: ${t.channel || 'none'}${channelInfo}${fired}`;
    });
    return { decision: 'deny', reason: lines.join('\n') };
  },
};

// ─── SDK 原生工具重定向（拦截并引导 AI 使用 Bash 版本）─────────────────────────

const SDK_CRON_REDIRECT = `❌ 请勿使用 SDK 内置的 CronCreate/CronDelete/CronList 工具，它们在本系统中无法持久化。
请改用以下 Bash 命令：
- 创建：Bash(__cron_create__ '{"cron":"...","prompt":"...","recurring":true}')
- 删除：Bash(__cron_delete__ '{"id":"任务ID"}')
- 列表：Bash(__cron_list__)`;

export const sdkCronCreateRedirect = {
  name: 'sdk_CronCreate_redirect',
  systemPrompt: '',
  match(hookInput) { return hookInput.tool_name === 'CronCreate'; },
  async execute() { return { decision: 'deny', reason: SDK_CRON_REDIRECT }; },
};

export const sdkCronDeleteRedirect = {
  name: 'sdk_CronDelete_redirect',
  systemPrompt: '',
  match(hookInput) { return hookInput.tool_name === 'CronDelete'; },
  async execute() { return { decision: 'deny', reason: SDK_CRON_REDIRECT }; },
};

export const sdkCronListRedirect = {
  name: 'sdk_CronList_redirect',
  systemPrompt: '',
  match(hookInput) { return hookInput.tool_name === 'CronList'; },
  async execute() { return { decision: 'deny', reason: SDK_CRON_REDIRECT }; },
};
