import isoGit, { _GitCommit, _GitPackIndex, _GitTree, _collect, } from "../../../vendored/isomorphic-git/index.js";
if (window) {
    // @ts-expect-error
    window.isoGit = isoGit;
}
/**
 * Use this to intercept your resoponse function to log the pack files interals
 * @param Uint8Array the body of a pack Response
 * @returns
 */
export async function inflatePackResponse(packResonseBody) {
    // parse pack response in the same way iso git does it in fetch
    const bodyResponse = await isoGit._parseUploadPackResponse([packResonseBody]);
    // body response now contains:
    // shallows - the commits that do have parents, but not in the shallow repo and therefore grafts are introduced pretending that these commits have no parents.(?)
    // https://git-scm.com/docs/shallow
    // unshallows - TODO check mechanism here
    const packfile = Buffer.from(await _collect(bodyResponse.packfile));
    const packfileSha = packfile.slice(-20).toString("hex");
    if (!packfileSha) {
        return "";
    }
    return {
        acks: bodyResponse.acks,
        nak: bodyResponse.nak,
        shallows: bodyResponse.shallows,
        unshallows: bodyResponse.unshallows,
        packfilePath: `objects/pack/pack-${packfileSha}.pack`,
        ...(await inflatePackfile(packfile)),
    };
}
export async function inflatePackfile(packfile) {
    // TODO check how to deal with external ref deltas here - do we want to try to get them locally?
    const getExternalRefDelta = (oid) => console.warn("trying to catch external ref", oid); // readObject({ fs, cache, gitdir, oid })
    const idx = await _GitPackIndex.fromPack({
        pack: packfile,
        getExternalRefDelta,
        onProgress: undefined,
    });
    const inflatedPack = {};
    const trees = {};
    // @ts-expect-error
    for (const hash of idx.hashes) {
        const object = await idx.read({ oid: hash });
        const typeKey = object.type + "s";
        if (!inflatedPack[typeKey]) {
            inflatedPack[typeKey] = {};
        }
        if (object.type === "tree") {
            trees[hash] = new _GitTree(object.object);
        }
        else if (object.type === "commit") {
            const commit = new _GitCommit(object.object);
            inflatedPack[typeKey][hash] = commit.parse();
        }
        else if (object.type === "blob") {
            object.string = object.object.toString();
            inflatedPack[typeKey][hash] = object;
        }
        else {
            inflatedPack[typeKey][hash] = object;
        }
    }
    Object.values(inflatedPack.commits || {}).forEach((commit) => {
        inflatedPack.trees[commit.tree] = extractTree(trees, commit.tree);
    });
    // add the remaining trees that are not part of commit trees
    inflatedPack.trees = { ...inflatedPack.trees, ...trees };
    return inflatedPack;
}
function extractTree(treeEntries, treeHash) {
    const tree = treeEntries[treeHash];
    if (!tree) {
        return {};
    }
    const extractedTree = {};
    tree._entries.forEach((entry) => {
        if (entry.type === "tree") {
            extractedTree[entry.path] = {
                children: extractTree(treeEntries, entry.oid),
                ...entry,
            };
        }
        else {
            extractedTree[entry.path] = entry;
        }
    });
    delete treeEntries[treeHash];
    return extractedTree;
}
