// Execution log route（KV 額度事故修復，2026-08-07；保留期＝P7，2026-08-09）。
// cypher-executor 對每次 workflow 執行 fire-and-forget POST /execution-log/record；
// executions.ts / portal-data.ts 讀 GET /execution-log 取代舊的 ANALYTICS_KV list/get。
// 形狀比照 recipe-stats.ts（同一種「cypher 寫、KBDB 存」的 fire-and-forget stat 端點）。
import { Hono } from 'hono';
import type { Bindings } from '../types';
import {
  recordExecutionLog,
  listExecutionLog,
  latestExecutionLog,
  getRetentionDays,
  setRetentionDays,
  cleanupExpiredLogs,
  DEFAULT_RETENTION_DAYS,
} from '../actions/execution-log';

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

// POST /execution-log/record — { workflow_id, owner_id?, verdict, duration_ms, message?, target? }
executionLogRoutes.post('/record', async (c) => {
  const body = await c.req.json().catch(() => null) as {
    workflow_id?: string;
    owner_id?: string | null;
    verdict?: string;
    duration_ms?: number;
    message?: string;
    target?: string | null;
  } | null;
  if (!body || !body.workflow_id || (body.verdict !== 'success' && body.verdict !== 'failed')) {
    return c.json({ success: false, error: 'workflow_id 與 verdict("success"|"failed") 必填' }, 400);
  }
  const result = await recordExecutionLog(c.env.DB, c.env, {
    workflow_id: body.workflow_id,
    owner_id: body.owner_id ?? null,
    verdict: body.verdict,
    duration_ms: typeof body.duration_ms === 'number' ? body.duration_ms : 0,
    message: body.message ?? '',
    target: body.target ?? null,
  });
  return c.json({ success: true, ...result });
});

// GET /execution-log?workflow_id=&owner_id=&limit= — 最近 N 次（降冪）
executionLogRoutes.get('/', async (c) => {
  const workflowId = c.req.query('workflow_id');
  if (!workflowId) return c.json({ success: false, error: 'workflow_id 必填' }, 400);
  const ownerId = c.req.query('owner_id') || undefined;
  const limitParam = c.req.query('limit');
  const limit = Math.min(Math.max(parseInt(limitParam || '10', 10) || 10, 1), 100);
  const executions = await listExecutionLog(c.env.DB, workflowId, ownerId, limit);
  return c.json({ success: true, executions });
});

// GET /execution-log/latest?workflow_id=&owner_id= — 最新一次（portal 卡片用）
executionLogRoutes.get('/latest', async (c) => {
  const workflowId = c.req.query('workflow_id');
  if (!workflowId) return c.json({ success: false, error: 'workflow_id 必填' }, 400);
  const ownerId = c.req.query('owner_id') || undefined;
  const execution = await latestExecutionLog(c.env.DB, workflowId, ownerId);
  return c.json({ success: true, execution });
});

// ── P7：保留期可設定（2026-08-09） ──────────────────────────────────────────

// GET /execution-log/retention?owner_id= — 讀某租戶目前的保留天數
// （回 retention_days: number | null；null＝該租戶已設「不刪除」）。owner_id 必填——
// 沒有租戶就沒有「誰的設定」這回事，讀無租戶的保留期用不到這支，走 DEFAULT_RETENTION_DAYS 常數即可。
executionLogRoutes.get('/retention', async (c) => {
  const ownerId = c.req.query('owner_id');
  if (!ownerId) return c.json({ success: false, error: 'owner_id 必填' }, 400);
  const retentionDays = await getRetentionDays(c.env.DB, ownerId);
  return c.json({ success: true, owner_id: ownerId, retention_days: retentionDays, default_days: DEFAULT_RETENTION_DAYS });
});

// PUT /execution-log/retention — body { owner_id, retention_days: number|null }
// retention_days=null＝「不刪除」（leo 08-07：「我願意花很多錢保存，不要刪除」，企業稽核選項）。
// retention_days=正整數＝自訂天數（覆蓋預設 90 天）。
executionLogRoutes.put('/retention', async (c) => {
  const body = (await c.req.json().catch(() => null)) as
    | { owner_id?: string; retention_days?: number | null }
    | null;
  if (!body || !body.owner_id) return c.json({ success: false, error: 'owner_id 必填' }, 400);
  const days = body.retention_days;
  if (days !== null && (typeof days !== 'number' || !Number.isFinite(days) || days <= 0)) {
    return c.json({ success: false, error: 'retention_days 必須是正整數，或 null（代表不刪除）' }, 400);
  }
  await setRetentionDays(c.env.DB, body.owner_id, days === null ? null : Math.round(days));
  return c.json({ success: true, owner_id: body.owner_id, retention_days: days === null ? null : Math.round(days) });
});

// POST /execution-log/cleanup — 清一批過期執行紀錄（見 actions/execution-log.ts 頂部註解：
// 呼叫端＝cypher-executor 既有的每分鐘 scheduled tick，一天呼叫一次，不是新排程基礎設施）。
// 內部維運端點，無 body；每次呼叫界限刪除量，長期多次呼叫可逐步清完累積量。
executionLogRoutes.post('/cleanup', async (c) => {
  const result = await cleanupExpiredLogs(c.env.DB);
  return c.json({ success: true, ...result });
});
