"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.discoverContainingGitRoot = discoverContainingGitRoot;
exports.ensureGitRepository = ensureGitRepository;
exports.ensureGitRemote = ensureGitRemote;
exports.pushCurrentHeadToRemoteBranch = pushCurrentHeadToRemoteBranch;
exports.assertCurrentHeadCanBePushed = assertCurrentHeadCanBePushed;
exports.hasUncommittedChanges = hasUncommittedChanges;
const promises_1 = require("node:fs/promises");
const node_path_1 = __importDefault(require("node:path"));
const native_git_cli_1 = require("./native-git-cli");
const remote_discovery_1 = require("./remote-discovery");
const remote_url_safety_1 = require("./remote-url-safety");
async function discoverContainingGitRoot(targetPath) {
    let current = node_path_1.default.resolve(targetPath);
    if (!(await pathExists(current))) {
        return null;
    }
    while (true) {
        if (await pathExists(node_path_1.default.join(current, ".git"))) {
            return current;
        }
        const parent = node_path_1.default.dirname(current);
        if (parent === current) {
            return null;
        }
        current = parent;
    }
}
async function ensureGitRepository(input) {
    await (0, promises_1.mkdir)(input.repositoryRoot, { recursive: true });
    if (await isGitRepository(input.repositoryRoot)) {
        return { initialized: false };
    }
    await (0, native_git_cli_1.runNativeGit)(input.repositoryRoot, [
        "init",
        "--initial-branch",
        input.defaultBranch,
    ]);
    return { initialized: true };
}
async function ensureGitRemote(input) {
    (0, remote_url_safety_1.assertRemoteUrlDoesNotContainCredentials)(input.remoteUrl);
    const existingUrl = await (0, remote_discovery_1.discoverGitRemoteUrl)(input.repositoryRoot, input.remoteName);
    if (existingUrl === input.remoteUrl) {
        return { added: false };
    }
    if (existingUrl) {
        throw new Error(`Git remote '${input.remoteName}' already points to ${(0, remote_url_safety_1.redactRemoteUrlCredentials)(existingUrl)}. Refusing to overwrite it with ${(0, remote_url_safety_1.redactRemoteUrlCredentials)(input.remoteUrl)}.`);
    }
    await (0, native_git_cli_1.runNativeGit)(input.repositoryRoot, [
        "remote",
        "add",
        input.remoteName,
        input.remoteUrl,
    ]);
    return { added: true };
}
async function pushCurrentHeadToRemoteBranch(input) {
    await assertCurrentHeadCanBePushed({
        repositoryRoot: input.repositoryRoot,
        remoteName: input.remoteName,
        branchName: input.branchName,
    });
    await (0, native_git_cli_1.runNativeGit)(input.repositoryRoot, ["push", "--no-verify", input.remoteName, `HEAD:${input.branchName}`], { credentials: input.credentials, suppressHooks: true });
}
async function assertCurrentHeadCanBePushed(input) {
    try {
        await (0, native_git_cli_1.readNativeGit)(input.repositoryRoot, [
            "rev-parse",
            "--verify",
            "HEAD^{commit}",
        ]);
    }
    catch {
        throw new Error(`Cannot push ${input.remoteName}/${input.branchName}: local HEAD does not point to a commit.`);
    }
}
async function hasUncommittedChanges(repositoryRoot) {
    try {
        const status = await (0, native_git_cli_1.readNativeGit)(repositoryRoot, [
            "status",
            "--porcelain=v1",
            "--untracked-files=all",
        ]);
        return status.trim().length > 0;
    }
    catch {
        return true;
    }
}
async function pathExists(filePath) {
    try {
        await (0, promises_1.access)(filePath);
        return true;
    }
    catch {
        return false;
    }
}
async function isGitRepository(repositoryRoot) {
    try {
        await (0, native_git_cli_1.readNativeGit)(repositoryRoot, ["rev-parse", "--git-dir"]);
        return true;
    }
    catch (error) {
        if ((0, native_git_cli_1.isNativeGitExitCode)(error, 128)) {
            return false;
        }
        return false;
    }
}
