'use strict';

/**
 * config-loader.js
 * ──────────────────────────────────────────────────────────
 * Wizard config 加载器
 *
 * 功能：
 *   1. 加载 JSON config 文件并注入 _dir（用于解析相对路径）
 *   2. 展开 steps 中的 $ref 引用（指向公共步骤片段）
 *
 * $ref 格式：
 *   { "$ref": "../../commons/gateway.steps.json#restart" }
 *       ↑ 文件路径（相对于当前 config 所在目录）   ↑ 步骤 key
 *
 *   如果不加 #key，则将整个文件的值视为步骤（需是数组或对象）。
 *
 * 公共步骤文件格式（commons/xxx.steps.json）：
 *   {
 *     "restart": { ...step对象... },
 *     "check-health": { ...step对象... }
 *   }
 */

const path = require('path');

// wizards/scripts/ 的绝对路径（config-loader.js 在 wizards/runner/，上两层就是 scripts/）
const SCRIPTS_DIR = path.resolve(__dirname, '../scripts');

/**
 * 加载并解析 wizard config
 * @param {string} configPath - 绝对路径
 * @returns {Object} 解析后的 config（steps 已展开 $ref）
 */
function loadConfig(configPath) {
  delete require.cache[require.resolve(configPath)];

  const raw     = require(configPath);
  const baseDir = path.dirname(configPath);

  const steps = _expandSteps(raw.steps || [], baseDir)
    .map(step => _resolveBuiltinVars(step));

  return { ...raw, steps, _dir: baseDir };
}

/**
 * 展开 steps 数组中的 $ref 项
 */
function _expandSteps(steps, baseDir) {
  const result = [];

  for (const step of steps) {
    if (step.$ref) {
      const expanded = _resolveRef(step.$ref, baseDir);
      if (Array.isArray(expanded)) {
        result.push(...expanded);
      } else {
        result.push(expanded);
      }
    } else {
      result.push(step);
    }
  }

  return result;
}

/**
 * 解析单个 $ref 字符串
 * @param {string} ref - "path/to/file.json#key"
 * @param {string} baseDir - 当前 config 所在目录
 */
function _resolveRef(ref, baseDir) {
  const [filePart, key] = ref.split('#');
  const absPath = path.resolve(baseDir, filePart);

  // 每次都清缓存，保持公共步骤文件可热更新
  delete require.cache[require.resolve(absPath)];
  const file = require(absPath);

  if (key) {
    if (!file[key]) {
      throw new Error(`[config-loader] $ref "${ref}" 中找不到 key "${key}"`);
    }
    return file[key];
  }

  return file;
}

/**
 * 展开内置变量（在 config 加载时一次性替换）
 *
 * 支持的内置变量：
 *   {scripts_dir}  →  wizards/scripts/ 的绝对路径
 *
 * 注意与用户动态输入的 {{var}} 区分：
 *   {scripts_dir}   加载时替换（静态）
 *   {{account_id}}  运行时由用户输入填充（动态）
 */
function _resolveBuiltinVars(step) {
  const VARS = { scripts_dir: SCRIPTS_DIR };

  function replace(str) {
    if (typeof str !== 'string') return str;
    return str.replace(/\{(\w+)\}/g, (_, key) =>
      Object.prototype.hasOwnProperty.call(VARS, key) ? VARS[key] : `{${key}}`
    );
  }

  if (!step.command) return step;

  return {
    ...step,
    command: {
      ...step.command,
      exec:     replace(step.command.exec),
      display:  replace(step.command.display),
      template: replace(step.command.template),
    },
  };
}


module.exports = { loadConfig };
