import { execa } from "execa";
import { debug } from "../engine/core/logger.js";
// ── 基础操作 ──
/** 执行 git 命令并返回标准输出 */
async function git(args, cwd) {
    const result = await execa("git", args, { cwd, timeout: 30_000 });
    return result.stdout;
}
/**
 * 检查指定目录是否为 Git 仓库。
 * @param cwd - 工作目录
 * @returns 是否为 Git 仓库
 */
export async function isGitRepo(cwd) {
    debug("Git操作", "检查是否为Git仓库 —", cwd);
    try {
        await execa("git", ["rev-parse", "--is-inside-work-tree"], { cwd, timeout: 5_000 });
        return true;
    }
    catch {
        return false;
    }
}
/**
 * 获取 Git 仓库根目录。
 * @param cwd - 工作目录
 * @returns 仓库根目录的绝对路径
 */
export async function getRootDir(cwd) {
    debug("Git操作", "获取仓库根目录 —", cwd);
    return (await git(["rev-parse", "--show-toplevel"], cwd)).trim();
}
/**
 * 获取当前分支名称。
 * @param cwd - 工作目录
 * @returns 当前分支名
 */
export async function getCurrentBranch(cwd) {
    debug("Git操作", "获取当前分支 —", cwd);
    return (await git(["rev-parse", "--abbrev-ref", "HEAD"], cwd)).trim();
}
/**
 * 检查工作区是否干净（无未提交的变更）。
 * @param cwd - 工作目录
 * @returns 工作区是否干净
 */
export async function isClean(cwd) {
    debug("Git操作", "检查工作区是否干净 —", cwd);
    const output = await git(["status", "--porcelain"], cwd);
    return output.trim().length === 0;
}
// ── 状态查询 ──
/**
 * 获取工作区文件状态列表。
 * @param cwd - 工作目录
 * @returns 文件状态数组
 */
export async function getStatus(cwd) {
    debug("Git操作", "获取文件状态列表");
    const output = await git(["status", "--porcelain", "-z"], cwd);
    if (!output)
        return [];
    const files = [];
    // -z 格式: XY PATH\0，未合并项为 XY ORIG_PATH\0 PATH\0，重命名为 XY ORIG_PATH\0 PATH\0
    const entries = output.split("\0").filter(Boolean);
    let i = 0;
    while (i < entries.length) {
        const entry = entries[i];
        if (entry.length < 3) {
            i++;
            continue;
        }
        const xy = entry.slice(0, 2);
        let filePath = entry.slice(3);
        // 重命名文件：下一个条目是新路径
        if ((xy[0] === "R" || xy[0] === "C") && i + 1 < entries.length) {
            filePath = entries[i + 1];
            i++;
        }
        files.push({ path: filePath, status: xyToStatus(xy) });
        i++;
    }
    return files;
}
/** 将 git status XY 状态码转换为语义化状态 */
function xyToStatus(xy) {
    if (xy.includes("?"))
        return "untracked";
    if (xy.includes("U") || xy === "AA" || xy === "DD")
        return "conflicted";
    if (xy[0] === "A" || xy[1] === "A")
        return "added";
    if (xy[0] === "D" || xy[1] === "D")
        return "deleted";
    if (xy[0] === "R")
        return "renamed";
    return "modified";
}
// ── 日志查询 ──
/**
 * 获取 Git 提交日志。
 * @param cwd - 工作目录
 * @param options - 查询选项（最大数量、起始日期、作者、路径过滤）
 * @returns 提交日志条目数组
 */
export async function getLog(cwd, options) {
    debug("Git操作", "获取提交日志");
    const args = ["log", "--format=%H%x00%h%x00%an%x00%ai%x00%s%x01"];
    if (options?.maxCount)
        args.push(`--max-count=${options.maxCount}`);
    if (options?.since)
        args.push(`--since=${options.since}`);
    if (options?.author)
        args.push(`--author=${options.author}`);
    args.push("--");
    if (options?.path)
        args.push(options.path);
    let output;
    try {
        output = await git(args, cwd);
    }
    catch {
        return [];
    }
    if (!output.trim())
        return [];
    return output.trim().split("\x01").filter(Boolean).map((entry) => {
        const parts = entry.trim().split("\x00");
        const [hash, shortHash, author, date, ...msgParts] = parts;
        return { hash, shortHash, author, date, message: msgParts.join("\x00") };
    });
}
/**
 * 获取贡献者提交统计（shortlog）。
 * @param cwd - 工作目录
 * @param since - 起始日期过滤（可选）
 * @returns 贡献者及其提交次数数组
 */
export async function getShortlog(cwd, since) {
    debug("Git操作", "获取贡献者统计");
    const args = ["shortlog", "-sn", "--all"];
    if (since)
        args.push(`--since=${since}`);
    const output = await git(args, cwd);
    if (!output.trim())
        return [];
    return output.trim().split("\n").map((line) => {
        const match = line.match(/^\s*(\d+)\s+(.+)$/);
        if (!match)
            return null;
        return { count: parseInt(match[1], 10), author: match[2].trim() };
    }).filter(Boolean);
}
// ── 差异查询 ──
/**
 * 获取差异统计信息（numstat 格式）。
 * @param cwd - 工作目录
 * @param options - 查询选项（是否包含暂存区、路径过滤）
 * @returns 差异统计块数组
 */
export async function getDiff(cwd, options) {
    debug("Git操作", "获取差异统计");
    const args = ["diff", "--numstat"];
    if (options?.cached)
        args.push("--cached");
    args.push("--");
    if (options?.path)
        args.push(options.path);
    const numstat = await git(args, cwd);
    if (!numstat.trim())
        return [];
    const hunks = [];
    for (const line of numstat.trim().split("\n")) {
        const parts = line.split("\t");
        if (parts.length >= 3) {
            hunks.push({
                file: parts[2],
                additions: parts[0] === "-" ? 0 : parseInt(parts[0], 10),
                deletions: parts[1] === "-" ? 0 : parseInt(parts[1], 10),
                patch: "",
            });
        }
    }
    return hunks;
}
/**
 * 获取指定文件的差异补丁。
 * @param cwd - 工作目录
 * @param filePath - 文件路径
 * @param options - 查询选项（是否包含暂存区）
 * @returns 差异补丁字符串
 */
export async function getDiffPatch(cwd, filePath, options) {
    debug("Git操作", "获取文件差异补丁 —", filePath);
    const args = ["diff"];
    if (options?.cached)
        args.push("--cached");
    args.push("--", filePath);
    return git(args, cwd);
}
// ── 逐行归属 ──
/**
 * 获取指定文件的逐行 Blame 信息。
 * @param cwd - 工作目录
 * @param filePath - 文件路径
 * @returns 逐行 Blame 信息数组
 */
export async function getBlame(cwd, filePath) {
    debug("Git操作", "获取文件Blame信息 —", filePath);
    const output = await git(["blame", "--porcelain", filePath], cwd);
    if (!output.trim())
        return [];
    const lines = [];
    let currentHash = "";
    let currentAuthor = "";
    let currentDate = "";
    let currentLine = 0;
    for (const line of output.split("\n")) {
        const headerMatch = line.match(/^([0-9a-f]{40})\s+(\d+)\s+(\d+)/);
        if (headerMatch) {
            currentHash = headerMatch[1].slice(0, 8);
            currentLine = parseInt(headerMatch[3], 10);
            continue;
        }
        if (line.startsWith("author ")) {
            currentAuthor = line.slice(7);
            continue;
        }
        if (line.startsWith("author-time ")) {
            const ts = parseInt(line.slice(12), 10);
            currentDate = new Date(ts * 1000).toISOString().split("T")[0];
            continue;
        }
        if (line.startsWith("\t")) {
            lines.push({
                line: currentLine,
                hash: currentHash,
                author: currentAuthor,
                date: currentDate,
                content: line.slice(1),
            });
        }
    }
    return lines;
}
// ── 分支操作 ──
/**
 * 列出所有本地分支。
 * @param cwd - 工作目录
 * @returns 分支信息数组（名称和是否为当前分支）
 */
export async function listBranches(cwd) {
    debug("Git操作", "列出所有分支");
    const output = await git(["branch", "--format=%(refname:short) %(HEAD)"], cwd);
    if (!output.trim())
        return [];
    return output.trim().split("\n").map((line) => {
        const [name, head] = line.trim().split(/\s+/);
        return { name, isCurrent: head === "*" };
    });
}
// ── 写操作 ──
/**
 * 将文件添加到暂存区。
 * @param cwd - 工作目录
 * @param paths - 要暂存的文件路径列表
 */
export async function add(cwd, paths) {
    debug("Git操作", "暂存文件", paths.join(", "));
    await git(["add", "--", ...paths], cwd); // -- 防止路径被解析为 git flag
}
/**
 * 创建提交。
 * @param cwd - 工作目录
 * @param message - 提交信息
 * @returns git commit 命令输出
 */
export async function commit(cwd, message) {
    debug("Git操作", "创建提交");
    return git(["commit", "-m", message], cwd);
}
/**
 * 推送到远程仓库。
 * @param cwd - 工作目录
 * @param remote - 远程名称（可选）
 * @param branch - 分支名称（可选）
 * @returns git push 命令输出
 */
export async function push(cwd, remote, branch) {
    debug("Git操作", "推送到远程", remote, branch);
    const args = ["push"];
    if (remote && branch) {
        args.push(remote, branch);
    }
    else if (remote) {
        args.push(remote);
    }
    return git(args, cwd);
}
/**
 * 获取两个分支的合并基点。
 * @param cwd - 工作目录
 * @param branchA - 分支 A 名称
 * @param branchB - 分支 B 名称
 * @returns 合并基点的 commit hash
 */
export async function getMergeBase(cwd, branchA, branchB) {
    debug("Git操作", "获取合并基点 —", branchA, branchB);
    return (await git(["merge-base", branchA, branchB], cwd)).trim();
}
/**
 * 获取远程仓库 URL。
 * @param cwd - 工作目录
 * @param remote - 远程名称，默认为 "origin"
 * @returns 远程 URL，未找到时返回 null
 */
export async function getRemoteUrl(cwd, remote = "origin") {
    debug("Git操作", "获取远程仓库URL —", remote);
    try {
        return (await git(["remote", "get-url", remote], cwd)).trim();
    }
    catch {
        return null;
    }
}
/**
 * 获取 HEAD 的短 commit hash。
 * @param cwd - 工作目录
 * @returns HEAD 的短 hash
 */
export async function getHeadCommitHash(cwd) {
    debug("Git操作", "获取HEAD commit hash");
    return (await git(["rev-parse", "--short", "HEAD"], cwd)).trim();
}
//# sourceMappingURL=operations.js.map