/**
 * Recipe transform 白名單實作
 * SDD: matrix/arcrun/.agents/specs/recipe-system/design.md §2.1
 *
 * 每個 transform 接 unknown，回 unknown。
 * 失敗策略：一律 throw，由 expander 包成 recipe 錯誤
 */

export type TransformFn = (value: unknown, arg?: string) => unknown;

const transforms: Record<string, TransformFn> = {
  json_array: (v) => JSON.stringify(v ?? []),

  to_string: (v) => {
    if (v === null || v === undefined) return '';
    if (typeof v === 'object') return JSON.stringify(v);
    return String(v);
  },

  join: (v, sep) => {
    if (!Array.isArray(v)) throw new Error('join: input 不是 array');
    return v.map((x) => (typeof x === 'string' ? x : JSON.stringify(x))).join(sep ?? '\n');
  },

  markdown_list: (v) => {
    if (!Array.isArray(v)) throw new Error('markdown_list: input 不是 array');
    return v.map((x) => `- ${typeof x === 'string' ? x : JSON.stringify(x)}`).join('\n');
  },

  extract_field: (v, field) => {
    if (!field) throw new Error('extract_field: 需要 field 參數，例如 extract_field:page_name');
    if (!Array.isArray(v)) throw new Error('extract_field: input 不是 array');
    return v.map((x) => (x && typeof x === 'object' ? (x as Record<string, unknown>)[field] : undefined));
  },

  first: (v) => {
    if (!Array.isArray(v)) return v;
    return v[0];
  },

  pluck_content: (v) => {
    if (!Array.isArray(v)) throw new Error('pluck_content: input 不是 array');
    return v
      .map((b) => (b && typeof b === 'object' ? String((b as Record<string, unknown>).content ?? '') : ''))
      .filter((s) => s.length > 0)
      .join('\n\n---\n\n');
  },
};

/** 解析 "name" 或 "name:arg" → 執行 transform */
export function applyTransform(value: unknown, spec: string): unknown {
  const colonIdx = spec.indexOf(':');
  const name = colonIdx === -1 ? spec : spec.slice(0, colonIdx);
  const arg = colonIdx === -1 ? undefined : spec.slice(colonIdx + 1);
  const fn = transforms[name];
  if (!fn) throw new Error(`未知 transform: ${name}`);
  return fn(value, arg);
}
