/**
 * 通用模板渲染器
 *
 * 支持的语法:
 * - ${variable} - 简单变量替换
 * - ${obj.prop} - 嵌套属性访问
 * - ${condition ? "trueValue" : "falseValue"} - 条件表达式
 * - ${FUNC_NAME()} - 函数调用（无参数）
 * - ${value / divisor} - 算术运算（除法）
 */

import type {
  TemplateContext,
  Template,
  RenderOptions,
  PromptContext,
  PromptTemplate,
  ToolNameMapping,
  ExtendedTemplateContext,
  TemplateFunctionRegistry,
} from './types.js';
import * as fs from 'fs';
import * as path from 'path';
import {
  CUSTOM_TIMEOUT_MS,
  MAX_TIMEOUT_MS,
  MAX_OUTPUT_CHARS,
} from '../constants/bash-tool.js';

/**
 * 获取嵌套属性值
 */
function getNestedValue(obj: Record<string, unknown>, pathStr: string): unknown {
  const parts = pathStr.split('.');
  let current: unknown = obj;

  for (const part of parts) {
    if (current === null || current === undefined) {
      return undefined;
    }
    if (typeof current === 'object') {
      current = (current as Record<string, unknown>)[part];
    } else {
      return undefined;
    }
  }

  return current;
}

/**
 * 查找三元运算符的各个部分
 * 处理嵌套引号的情况
 */
function findTernaryOperator(
  expr: string
): { condition: string; trueValue: string; falseValue: string } | null {
  let depth = 0;
  let inString: string | null = null;
  let questionPos = -1;
  let colonPos = -1;

  for (let i = 0; i < expr.length; i++) {
    const char = expr[i];
    const prevChar = i > 0 ? expr[i - 1] : '';

    // 处理字符串边界
    if ((char === '"' || char === "'" || char === '`') && prevChar !== '\\') {
      if (inString === null) {
        inString = char;
      } else if (inString === char) {
        inString = null;
      }
      continue;
    }

    // 如果在字符串中，跳过
    if (inString !== null) continue;

    // 处理括号深度
    if (char === '(' || char === '[' || char === '{') {
      depth++;
    } else if (char === ')' || char === ']' || char === '}') {
      depth--;
    }

    // 只在顶层寻找 ? 和 :
    if (depth === 0) {
      if (char === '?' && questionPos === -1) {
        questionPos = i;
      } else if (char === ':' && questionPos !== -1 && colonPos === -1) {
        colonPos = i;
      }
    }
  }

  if (questionPos === -1 || colonPos === -1) {
    return null;
  }

  return {
    condition: expr.substring(0, questionPos).trim(),
    trueValue: expr.substring(questionPos + 1, colonPos).trim(),
    falseValue: expr.substring(colonPos + 1).trim(),
  };
}

/**
 * 安全的表达式求值器
 * 支持简单的属性访问和三元运算符
 */
function evaluateExpression(
  expr: string,
  context: TemplateContext,
  options: RenderOptions = {}
): string {
  // 移除首尾空格
  expr = expr.trim();

  // 处理三元运算符: condition ? trueValue : falseValue
  const ternaryMatch = findTernaryOperator(expr);
  if (ternaryMatch) {
    const { condition, trueValue, falseValue } = ternaryMatch;
    const conditionResult = evaluateExpression(condition, context, options);
    // 将结果转换为布尔值
    const isTruthy =
      conditionResult !== '' &&
      conditionResult !== 'false' &&
      conditionResult !== 'undefined' &&
      conditionResult !== 'null' &&
      conditionResult !== '0';
    return isTruthy
      ? evaluateExpression(trueValue, context, options)
      : evaluateExpression(falseValue, context, options);
  }

  // 处理算术运算（除法）: value / divisor 或 FUNC() / divisor
  // 注意：必须在函数调用之前处理，因为 FUNC()/60000 需要先拆分
  const divMatch = expr.match(/^(.+?)\s*\/\s*(\d+)$/);
  if (divMatch) {
    const left = evaluateExpression(divMatch[1].trim(), context, options);
    const divisor = parseInt(divMatch[2], 10);
    const leftNum = parseFloat(left);
    if (!isNaN(leftNum) && divisor !== 0) {
      return String(Math.floor(leftNum / divisor));
    }
  }

  // 处理函数调用: FUNC_NAME()
  const funcMatch = expr.match(/^([A-Za-z_][A-Za-z0-9_]*)\(\)$/);
  if (funcMatch) {
    const funcName = funcMatch[1];
    const functions = (context as ExtendedTemplateContext).__functions__;
    if (functions && typeof functions[funcName] === 'function') {
      return String(functions[funcName]());
    }
    // 未找到函数，继续尝试作为变量处理
  }

  // 处理字符串字面量: "string" 或 'string' 或 `string`
  const stringMatch = expr.match(/^["'`]([\s\S]*)["'`]$/);
  if (stringMatch) {
    // 递归处理字符串中的变量插值
    return renderTemplate(stringMatch[1], context, options);
  }

  // 处理布尔字面量
  if (expr === 'true') return 'true';
  if (expr === 'false') return '';

  // 处理属性访问: obj.prop.subprop
  let value = getNestedValue(context, expr);

  // 如果在主上下文中找不到，且是单层变量名，尝试直接访问
  // 这支持在 context 根级别定义的变量（如 GREP_TOOL_NAME）
  if (value === undefined && !expr.includes('.')) {
    value = context[expr];
  }

  if (value === undefined) {
    if (options.throwOnUndefined) {
      throw new Error(`Undefined variable: ${expr}`);
    }
    if (options.debug) {
      console.warn(`[Template] Undefined variable: ${expr}`);
    }
    return options.undefinedValue ?? '';
  }

  // 布尔值转换
  if (typeof value === 'boolean') {
    return value ? 'true' : '';
  }

  return String(value);
}

/**
 * 渲染模板
 *
 * @param template 模板字符串
 * @param context 上下文变量
 * @param options 渲染选项
 * @returns 渲染后的字符串
 */
export function renderTemplate(
  template: string,
  context: TemplateContext,
  options: RenderOptions = {}
): string {
  // 匹配 ${...} 模式，支持嵌套括号和字符串
  const result: string[] = [];
  let i = 0;

  while (i < template.length) {
    // 查找 ${
    const start = template.indexOf('${', i);
    if (start === -1) {
      result.push(template.substring(i));
      break;
    }

    // 添加 ${ 之前的文本
    result.push(template.substring(i, start));

    // 查找匹配的 }
    let depth = 1;
    let j = start + 2;
    let inString: string | null = null;

    while (j < template.length && depth > 0) {
      const char = template[j];
      const prevChar = j > 0 ? template[j - 1] : '';

      // 处理字符串边界
      if ((char === '"' || char === "'" || char === '`') && prevChar !== '\\') {
        if (inString === null) {
          inString = char;
        } else if (inString === char) {
          inString = null;
        }
      } else if (inString === null) {
        if (char === '{') depth++;
        else if (char === '}') depth--;
      }

      j++;
    }

    if (depth !== 0) {
      // 未找到匹配的 }，保留原文
      result.push(template.substring(start, j));
    } else {
      // 提取表达式并求值
      const expression = template.substring(start + 2, j - 1);
      try {
        const value = evaluateExpression(expression, context, options);
        result.push(value);
      } catch (error) {
        if (options.debug) {
          console.warn(`[Template] Expression evaluation failed: ${expression}`, error);
        }
        result.push(`\${${expression}}`); // 保留原始文本
      }
    }

    i = j;
  }

  return result.join('');
}

/**
 * 渲染 Template 对象
 */
export function render(templateObj: Template, context: TemplateContext, options?: RenderOptions): string {
  return renderTemplate(templateObj.template, context, options);
}

// ============================================
// Agent 特定函数（Prompt Template）
// ============================================

/**
 * 渲染提示词模板（Agent 特定版本）
 * 将 custom 中的变量合并到顶层，以支持直接引用（如 ${GREP_TOOL_NAME}）
 */
export function renderPromptTemplate(
  template: string,
  context: PromptContext,
  options: RenderOptions = {}
): string {
  // 将 custom 中的变量合并到顶层上下文，这样 ${GREP_TOOL_NAME} 可以直接访问
  const flattenedContext: Record<string, unknown> = {
    ...context,
    ...context.custom,
  };
  return renderTemplate(template, flattenedContext, options);
}

/**
 * 渲染提示词模板对象（Agent 特定版本）
 */
export function renderPrompt(
  promptTemplate: PromptTemplate,
  context: PromptContext,
  options?: RenderOptions
): string {
  // 将 custom 中的变量合并到顶层上下文
  const flattenedContext: Record<string, unknown> = {
    ...context,
    ...context.custom,
  };
  return render({ ...promptTemplate }, flattenedContext, options);
}

/**
 * 默认工具名称映射
 */
export const DEFAULT_TOOL_NAMES: ToolNameMapping = {
  glob: 'glob',
  grep: 'grep',
  read: 'read_file',
  write: 'write_file',
  edit: 'edit_file',
  bash: 'bash',
  askUserQuestion: 'ask_user_question',
  exitPlanMode: 'exit_plan_mode',
  enterPlanMode: 'enter_plan_mode',
  task: 'task',
  todoRead: 'todoread',
  todoWrite: 'todowrite',
  webSearch: 'web_search',
  webExtract: 'web_extract',
  gitStatus: 'git_status',
  gitDiff: 'git_diff',
  gitLog: 'git_log',
  gitBranch: 'git_branch',
  repoMap: 'repo_map',
};

/**
 * 创建默认的提示词上下文
 */
export function createDefaultContext(overrides?: Partial<PromptContext>): PromptContext {
  const homeDir = process.env.HOME || process.env.USERPROFILE || '';
  const workdir = process.cwd();

  return {
    tools: {
      ...DEFAULT_TOOL_NAMES,
      ...overrides?.tools,
    },
    plan: {
      isActive: false,
      planExists: false,
      planFilePath: path.join(homeDir, '.ai-terminal-assistant', 'plan', 'plan.md'),
      allowedWritePaths: [path.join(homeDir, '.ai-terminal-assistant', 'plan', '*')],
      ...overrides?.plan,
    },
    env: {
      workdir,
      isGitRepo: fs.existsSync(path.join(workdir, '.git')),
      platform: process.platform,
      date: new Date().toISOString().split('T')[0],
      homeDir,
      ...overrides?.env,
    },
    agent: {
      name: 'build',
      mode: 'primary',
      isSubagent: false,
      ...overrides?.agent,
    },
    custom: overrides?.custom,
  };
}

/**
 * 检查计划文件是否存在
 */
export function checkPlanFileExists(planFilePath: string): boolean {
  try {
    fs.accessSync(planFilePath);
    return true;
  } catch {
    return false;
  }
}

/**
 * 创建 Plan 模式上下文
 */
export function createPlanContext(options: {
  planFilePath?: string;
  workdir?: string;
  isSubagent?: boolean;
}): PromptContext {
  const homeDir = process.env.HOME || process.env.USERPROFILE || '';
  const planPath =
    options.planFilePath || path.join(homeDir, '.ai-terminal-assistant', 'plan', 'plan.md');
  const workdir = options.workdir || process.cwd();

  return createDefaultContext({
    plan: {
      isActive: true,
      planExists: checkPlanFileExists(planPath),
      planFilePath: planPath,
      allowedWritePaths: [path.join(homeDir, '.ai-terminal-assistant', 'plan', '*')],
    },
    env: {
      workdir,
      isGitRepo: fs.existsSync(path.join(workdir, '.git')),
      platform: process.platform,
      date: new Date().toISOString().split('T')[0],
      homeDir,
    },
    agent: {
      name: 'plan',
      mode: options.isSubagent ? 'subagent' : 'primary',
      isSubagent: options.isSubagent || false,
    },
  });
}

/**
 * 将驼峰命名转换为大写下划线命名
 * 例如: askUserQuestion -> ASK_USER_QUESTION
 */
function camelToUpperSnake(str: string): string {
  return str.replace(/[A-Z]/g, (c) => `_${c}`).toUpperCase();
}

/**
 * 创建工具描述渲染上下文
 *
 * 除了标准的 PromptContext 变量外，还会在 custom 中添加大写形式的工具名变量，
 * 以兼容 Claude Code 官方提示词格式（如 ${GREP_TOOL_NAME}）。
 *
 * 支持的变量格式：
 * - ${tools.grep} - 小写驼峰形式（项目内部风格）
 * - ${GREP_TOOL_NAME} - 大写下划线形式（Claude Code 官方风格）
 *
 * 支持的函数调用：
 * - ${CUSTOM_TIMEOUT_MS()} - 最大超时时间（毫秒）
 * - ${MAX_TIMEOUT_MS()} - 默认超时时间（毫秒）
 * - ${MAX_OUTPUT_CHARS()} - 输出截断限制（字符数）
 */
export function createToolDescriptionContext(
  overrides?: Partial<PromptContext>
): PromptContext & { __functions__: TemplateFunctionRegistry } {
  const base = createDefaultContext(overrides);

  // 将 tools 映射转为大写变量放入 custom
  const toolVars: Record<string, string> = {};
  for (const [key, value] of Object.entries(base.tools)) {
    // glob -> GLOB_TOOL_NAME
    // askUserQuestion -> ASK_USER_QUESTION_TOOL_NAME
    const upperKey = camelToUpperSnake(key) + '_TOOL_NAME';
    toolVars[upperKey] = value;
  }

  // 注册模板函数
  const functions: TemplateFunctionRegistry = {
    CUSTOM_TIMEOUT_MS: () => CUSTOM_TIMEOUT_MS,
    MAX_TIMEOUT_MS: () => MAX_TIMEOUT_MS,
    MAX_OUTPUT_CHARS: () => MAX_OUTPUT_CHARS,
  };

  return {
    ...base,
    custom: { ...base.custom, ...toolVars },
    __functions__: functions,
  };
}
