/**
 * Executions routes — LI SDD M2.1
 *
 * 對應 .agents/specs/llm-interface/ Milestone 2.1。給 AI 看 workflow 執行狀態的端點。
 *
 * - GET /executions/paused — 列當前所有 paused 的 workflow（等 callback resume）
 * - GET /executions/:task_id — 看單一 paused state 細節（含 trace、graph、node id）
 * - GET /workflows/:name/executions — 列某 workflow 最近 N 次執行 verdict
 *
 * 設計：純讀，無 side effect。所有路由要 api_key auth（防偷看他人 workflow state）。
 */

import { Hono } from 'hono';
import type { Bindings } from '../types';
import { listPausedRunsByApiKey } from '../lib/paused-runs';
import { kbdbBase } from './kbdb-proxy';

export const executionsRouter = new Hono<{ Bindings: Bindings }>();

/**
 * GET /executions/paused — 列當前 api_key 下所有 paused workflow
 *
 * 走 per-user index `paused_idx:{api_key}`（單 KV get，強 consistent，無 KV list 延遲）
 * 取代舊的 `paused_run:*` prefix scan（CF KV list 30-60 秒 eventual consistent）
 */
executionsRouter.get('/executions/paused', async (c) => {
  const apiKey = c.req.header('X-Arcrun-API-Key');
  if (!apiKey) {
    return c.json({
      ok: false,
      error_code: 'auth_missing',
      human_message: '缺 X-Arcrun-API-Key header',
      next_actions: ['call /me 取得你的 ak_xxx，加進 header'],
    }, 401);
  }

  const limitParam = c.req.query('limit');
  const limit = Math.min(Math.max(parseInt(limitParam || '20', 10), 1), 100);

  const paused = await listPausedRunsByApiKey(c.env.EXEC_CONTEXT, apiKey, limit);

  return c.json({
    ok: true,
    data: { count: paused.length, paused },
    hints: paused.length > 0
      ? [`${paused.length} 個 workflow 等 callback resume。call get_execution_trace(task_id) 看細節`]
      : ['沒有任何 paused workflow'],
  });
});

/**
 * GET /executions/:task_id — 看單一 paused workflow 的 state（trace、graph、context）
 *
 * task_id 來源：trigger workflow 時 response 含 paused 結果，task_id 在 error 字串裡，
 * 或前端 list_paused_executions 回的 task_id。
 *
 * 隔離：只能讀自己 api_key 的 state。
 */
executionsRouter.get('/executions/:task_id', async (c) => {
  const apiKey = c.req.header('X-Arcrun-API-Key');
  if (!apiKey) {
    return c.json({
      ok: false,
      error_code: 'auth_missing',
      human_message: '缺 X-Arcrun-API-Key header',
      next_actions: ['加 X-Arcrun-API-Key header'],
    }, 401);
  }

  const taskId = c.req.param('task_id');
  const raw = await c.env.EXEC_CONTEXT.get(`paused_run:${taskId}`);

  if (!raw) {
    return c.json({
      ok: false,
      error_code: 'not_found',
      human_message: `task_id "${taskId}" 沒對應的 paused state（可能已 resume 完、過 24h TTL 被 GC、或從未存在）`,
      next_actions: [
        'call /executions/paused 看當前所有 paused，確認 task_id 正確',
        '若該 workflow 不是 paused 型，看 /workflows/:name/executions 查歷史 verdict',
      ],
    }, 404);
  }

  let state: {
    run_id: string;
    graph?: unknown;
    paused_node_id: string;
    paused_context?: Record<string, unknown>;
    paused_pending_result?: Record<string, unknown>;
    trace_so_far?: unknown;
    api_key?: string;
    expires_at?: number;
  };
  try {
    state = JSON.parse(raw);
  } catch {
    return c.json({
      ok: false,
      error_code: 'internal_error',
      human_message: 'paused state JSON 損毀',
      next_actions: ['告訴 leo / 平台維護者'],
    }, 500);
  }

  if (state.api_key !== apiKey) {
    return c.json({
      ok: false,
      error_code: 'not_found',  // 不洩漏存在性
      human_message: `task_id "${taskId}" 找不到`,
      next_actions: ['確認 task_id 屬於你 (用 /executions/paused 列出)'],
    }, 404);
  }

  return c.json({
    ok: true,
    data: {
      task_id: taskId,
      run_id: state.run_id,
      paused_node_id: state.paused_node_id,
      paused_context: state.paused_context,
      paused_pending_result: state.paused_pending_result,
      trace_so_far: state.trace_so_far,
      expires_at: state.expires_at,
    },
    hints: [
      'paused 狀態 = workflow 等 daemon callback。等對應 service 回 POST /workflows/resume 即可繼續',
      '若 daemon 掛了，看 expires_at — 過 24h KV TTL 會 GC 此 state',
    ],
  });
});

/**
 * GET /workflows/:name/executions — 看某 workflow 最近 N 次執行 verdict
 *
 * KV 額度事故修復（2026-08-07）：改打 KBDB `GET /execution-log`（原走 ANALYTICS_KV
 * `stats:{workflowId}:*` prefix scan，免費層 list 也是 1,000/日，裝十幾支 workflow
 * 的實例刷 90 次 portal 就見底）。KBDB＝API-as-Wall（leo 2026-06-14）：本路由**不直連
 * 任何 D1**，一律走 HTTP，連法比照既有 kbdbBase() 慣例（kbdb-proxy.ts）。
 *
 * workflowId 等於 webhook name（execution-logger 寫入時用 graph.id ?? name，與舊 KV
 * key 同語意，沿用既有限制不在這次修復裡處理）。
 */
executionsRouter.get('/workflows/:name/executions', async (c) => {
  const apiKey = c.req.header('X-Arcrun-API-Key');
  if (!apiKey) {
    return c.json({
      ok: false,
      error_code: 'auth_missing',
      human_message: '缺 X-Arcrun-API-Key header',
      next_actions: ['加 X-Arcrun-API-Key header'],
    }, 401);
  }

  const name = c.req.param('name');
  const limitParam = c.req.query('limit');
  const limit = Math.min(Math.max(parseInt(limitParam || '10', 10), 1), 100);

  // 確認 workflow 是該 api_key 的（防偷看他人）
  const wfRaw = await c.env.WEBHOOKS.get(`${apiKey}:wf:${name}`, 'text');
  if (!wfRaw) {
    return c.json({
      ok: false,
      error_code: 'not_found',
      human_message: `workflow "${name}" 不存在或不屬於你`,
      next_actions: ['call /webhooks/named 看你有什麼 workflow'],
    }, 404);
  }

  const { base, headers } = kbdbBase(c.env);
  const params = new URLSearchParams({ workflow_id: name, owner_id: apiKey, limit: String(limit) });
  const kbdbRes = await fetch(`${base}/execution-log?${params.toString()}`, { headers });
  const kbdbBody = await kbdbRes.json().catch(() => null) as { success?: boolean; executions?: Array<{
    verdict: string; duration_ms: number; message: string; target?: string; recorded_at: number;
  }> } | null;

  const executions = (kbdbRes.ok && kbdbBody?.success ? kbdbBody.executions ?? [] : []).map((r) => ({
    timestamp: String(r.recorded_at),
    workflow_id: name,
    verdict: r.verdict,
    duration_ms: r.duration_ms,
    message: r.message ?? '',
    ...(r.target ? { target: r.target } : {}),
  }));

  return c.json({
    ok: true,
    data: {
      workflow_name: name,
      count: executions.length,
      executions,
    },
    hints: executions.length === 0
      ? ['尚未有任何執行紀錄。先 call /webhooks/named/:name/trigger 跑一次']
      : [`最近 ${executions.length} 次。看到 verdict=failed 的，call /executions/:task_id 看 paused state 或繼續 debug`],
  });
});
