/**
 * YAML 处理工具函数
 *
 * 提供 YAML 配置文件的读取、解析、生成和路径匹配功能
 */
import path from 'node:path';
import { promises as fs } from 'node:fs';
import * as yaml from 'js-yaml';
import { createLogger } from './logger.js';
const log = createLogger('yaml-utils');
/**
 * 检查 YAML 配置中是否有 agent 的 path 匹配目标路径
 * path 字段格式支持：modules\x 或 modules/x
 *
 * @param yamlContent - YAML 内容
 * @param targetRelativePath - 目标相对路径
 * @returns 匹配的 agent path，无匹配则返回 null
 */
export function hasMatchingAgentPath(yamlContent, targetRelativePath) {
    try {
        const parsed = yaml.load(yamlContent);
        if (!parsed || typeof parsed !== 'object') {
            return null;
        }
        const agents = parsed['agent'];
        if (!Array.isArray(agents)) {
            return null;
        }
        // 标准化目标路径（统一使用 / 分隔符）
        const normalizedTarget = targetRelativePath.replace(/\\/g, '/');
        for (const agent of agents) {
            if (!agent || typeof agent !== 'object') {
                continue;
            }
            const agentPath = agent['path'];
            if (typeof agentPath !== 'string') {
                continue;
            }
            // 标准化配置中的 path
            const normalizedAgentPath = agentPath.replace(/\\/g, '/');
            // 匹配逻辑：
            // 1. 精确匹配
            // 2. 如果目标是 "."（当前目录），配置中 path 为 "." 或空字符串也算匹配
            if (normalizedAgentPath === normalizedTarget) {
                return agentPath;
            }
            // 特殊处理：当前目录匹配
            if (normalizedTarget === '.' && (normalizedAgentPath === '.' || normalizedAgentPath === '')) {
                return agentPath;
            }
        }
        return null;
    }
    catch {
        return null;
    }
}
/**
 * 从 YAML 配置中提取匹配的 agent 配置，或生成模板
 *
 * @param yamlContent - YAML 内容
 * @param targetRelativePath - 目标相对路径
 * @returns 提取结果
 */
export function extractAgentConfigOrTemplate(yamlContent, targetRelativePath) {
    try {
        const parsed = yaml.load(yamlContent);
        if (!parsed || typeof parsed !== 'object') {
            return { content: yamlContent, isTemplate: false, projectFromSibling: null };
        }
        const agents = parsed['agent'];
        if (!Array.isArray(agents)) {
            return { content: yamlContent, isTemplate: false, projectFromSibling: null };
        }
        // 标准化目标路径（统一使用 "/" 分隔符）
        const normalizedTarget = targetRelativePath.replace(/\\/g, '/');
        // 查找匹配的 agent
        for (const agent of agents) {
            if (!agent || typeof agent !== 'object') {
                continue;
            }
            const agentObj = agent;
            const agentPath = agentObj['path'];
            if (typeof agentPath !== 'string') {
                continue;
            }
            const normalizedAgentPath = agentPath.replace(/\\/g, '/');
            // 匹配逻辑：
            // 1. 精确匹配
            // 2. 如果目标是 "."（当前目录），配置中 path 为 "." 或空字符串也算匹配
            const isMatch = normalizedAgentPath === normalizedTarget ||
                (normalizedTarget === '.' && (normalizedAgentPath === '.' || normalizedAgentPath === ''));
            if (isMatch) {
                // 找到匹配的 agent，只返回这一项（确保 path 使用 "/" 分隔符）
                const normalizedAgentObj = { ...agentObj, path: normalizedAgentPath };
                const singleAgentYaml = yaml.dump({ agent: [normalizedAgentObj] }, {
                    indent: 2,
                    lineWidth: -1,
                    quotingType: '"',
                    forceQuotes: false,
                });
                return { content: singleAgentYaml, isTemplate: false, projectFromSibling: null };
            }
        }
        // 没有匹配的 agent，生成模板
        // 先尝试从兄弟项获取 project 值
        let projectValue = null;
        for (const agent of agents) {
            if (!agent || typeof agent !== 'object') {
                continue;
            }
            const agentObj = agent;
            if (typeof agentObj['project'] === 'string') {
                projectValue = agentObj['project'];
                break;
            }
        }
        // 生成模板（path 使用 "/" 分隔符）
        const template = {
            agent: [
                {
                    name: '',
                    path: normalizedTarget,
                    project: projectValue || '',
                    description: '',
                    prompt: '',
                },
            ],
        };
        const templateYaml = yaml.dump(template, {
            indent: 2,
            lineWidth: -1,
            quotingType: '"',
            forceQuotes: false,
        });
        return { content: templateYaml, isTemplate: true, projectFromSibling: projectValue };
    }
    catch {
        return { content: yamlContent, isTemplate: false, projectFromSibling: null };
    }
}
/**
 * 生成空模板
 * 注意：path 字段留空，在写入时根据工作目录自动计算
 *
 * @param _targetRelativePath - 目标相对路径（未使用）
 * @returns 空模板 YAML 内容
 */
export function generateEmptyTemplate(_targetRelativePath) {
    const normalizedTargetPath = String(_targetRelativePath || '.')
        .trim()
        .replace(/\\/g, '/') || '.';
    const template = {
        agent: [
            {
                name: '',
                path: normalizedTargetPath,
                project: '',
                description: '',
                prompt: '',
            },
        ],
    };
    return yaml.dump(template, {
        indent: 2,
        lineWidth: -1,
        quotingType: '"',
        forceQuotes: false,
    });
}
/**
 * 自动填充 YAML 配置中的 path 字段
 * 如果 path 为空、未填写或只有空白字符，则使用工作目录相对于项目根目录的路径
 *
 * @param ymlContent - YAML 配置内容
 * @param workspaceRelativePath - 工作目录相对于项目根目录的路径
 * @returns 处理后的 YAML 内容
 */
export function autoFillPathInYml(ymlContent, workspaceRelativePath) {
    try {
        const parsed = yaml.load(ymlContent);
        if (!parsed || typeof parsed !== 'object') {
            return ymlContent;
        }
        const config = parsed;
        if (!config.agent || !Array.isArray(config.agent)) {
            return ymlContent;
        }
        let modified = false;
        for (const agent of config.agent) {
            if (agent) {
                // 检查 path 是否为空、未定义或只有空白字符
                const pathValue = agent.path;
                const isPathEmpty = pathValue === undefined ||
                    pathValue === null ||
                    String(pathValue).trim() === '';
                if (isPathEmpty) {
                    agent.path = workspaceRelativePath;
                    modified = true;
                }
            }
        }
        if (modified) {
            return yaml.dump(config, {
                indent: 2,
                lineWidth: -1,
                quotingType: '"',
                forceQuotes: false,
            });
        }
        return ymlContent;
    }
    catch {
        // 解析失败，返回原内容
        return ymlContent;
    }
}
/**
 * 向上查找并加载 YAML 配置文件
 *
 * 查找逻辑：
 * 1. 先检查工作目录下是否有配置文件，检查 path 是否匹配
 * 2. 如果不匹配，向上查找父目录的配置文件，检查 path 是否匹配
 * 3. 找到匹配的配置 → 使用该配置
 * 4. 所有层级都没有匹配的配置 → 使用最后一个找到的配置（或在工作目录创建）
 *
 * 例如：工作目录 D:\a\b\c\d，相对路径 vibe-coding/my.yml
 * 第1次查找：D:\a\b\c\d\vibe-coding\my.yml，匹配 path="."
 * 第2次查找：D:\a\b\c\vibe-coding\my.yml，匹配 path="d"
 * 第3次查找：D:\a\b\vibe-coding\my.yml，匹配 path="c/d"
 * ...
 */
export async function loadYmlWithUpwardSearch(workspacePath, relativePath) {
    const normalizedWorkspace = path.resolve(workspacePath);
    const normalizedRelative = relativePath.replace(/\//g, path.sep);
    const absoluteInitialPath = path.resolve(normalizedWorkspace, normalizedRelative);
    // 记录最后一次找到的配置文件（用于所有层级都不匹配时回退）
    let lastFoundConfig = null;
    // 首先尝试从工作目录读取
    try {
        const content = await fs.readFile(absoluteInitialPath, 'utf-8');
        log.debug(`工作目录下找到配置: ${absoluteInitialPath}`);
        // 当前目录的配置文件，工作目录相对于自己的相对路径是 "."
        const workspaceRelativeToSelf = '.';
        const matchedPath = hasMatchingAgentPath(content, workspaceRelativeToSelf);
        if (matchedPath) {
            // 找到匹配的 path，直接使用
            log.debug(`当前目录配置匹配 path: ${matchedPath}`);
            return { content, resolvedPath: absoluteInitialPath, foundInParent: false, matchedAgentPath: matchedPath };
        }
        // 当前目录配置不匹配，记录下来继续向上查找
        log.debug(`当前目录配置不匹配，继续向上查找`);
        lastFoundConfig = { content, resolvedPath: absoluteInitialPath };
    }
    catch (err) {
        const error = err;
        if (error?.code !== 'ENOENT') {
            throw err;
        }
    }
    // 从工作目录的父目录开始向上查找
    let currentDir = normalizedWorkspace;
    const root = path.parse(currentDir).root;
    while (currentDir && currentDir !== root) {
        const parentDir = path.dirname(currentDir);
        if (parentDir === currentDir) {
            break; // 已到达根目录
        }
        // 计算工作目录相对于父目录的相对路径（即 agent 的 path 字段值）
        const workspaceRelativeToParent = path.relative(parentDir, normalizedWorkspace);
        const candidatePath = path.join(parentDir, normalizedRelative);
        try {
            const content = await fs.readFile(candidatePath, 'utf-8');
            log.debug(`上层找到配置文件: ${candidatePath}`);
            // 检查是否有匹配的 agent path
            const matchedPath = hasMatchingAgentPath(content, workspaceRelativeToParent);
            log.debug(`相对路径: ${workspaceRelativeToParent}, 匹配的agent path: ${matchedPath || '无'}`);
            if (matchedPath) {
                // 找到匹配的配置，返回
                return {
                    content,
                    resolvedPath: candidatePath,
                    foundInParent: true,
                    matchedAgentPath: matchedPath,
                };
            }
            // 不匹配，记录下来继续向上查找
            lastFoundConfig = { content, resolvedPath: candidatePath };
        }
        catch (err) {
            const error = err;
            if (error?.code !== 'ENOENT') {
                throw err;
            }
        }
        currentDir = parentDir;
    }
    // 所有层级都没有找到匹配的配置
    if (lastFoundConfig) {
        // 使用最后一个找到的配置文件（需要入驻）
        log.debug(`所有层级都不匹配，使用最后找到的配置: ${lastFoundConfig.resolvedPath}`);
        return {
            content: lastFoundConfig.content,
            resolvedPath: lastFoundConfig.resolvedPath,
            foundInParent: lastFoundConfig.resolvedPath !== absoluteInitialPath,
            matchedAgentPath: null,
        };
    }
    // 完全没有配置文件，将在工作目录下创建
    log.debug(`未找到配置，将在工作目录创建: ${absoluteInitialPath}`);
    return { content: null, resolvedPath: absoluteInitialPath, foundInParent: false, matchedAgentPath: null };
}
