import { createHash } from "node:crypto";
import fs from "node:fs/promises";
export const PIPELINE_EXECUTION_LEDGER_SCHEMA_VERSION = "1";
export async function fileSha256IfPresent(filePath) {
    if (!filePath)
        return null;
    try {
        const content = await fs.readFile(filePath);
        return createHash("sha256").update(content).digest("hex");
    }
    catch (error) {
        const code = error.code;
        if (code === "ENOENT" || code === "ENOTDIR")
            return null;
        throw error;
    }
}
export async function fileExists(filePath) {
    if (!filePath)
        return false;
    try {
        await fs.access(filePath);
        return true;
    }
    catch {
        return false;
    }
}
export async function buildOutputHashes(outputRefs) {
    const entries = await Promise.all(outputRefs.map(async (outputRef) => [
        outputRef,
        await fileSha256IfPresent(outputRef),
    ]));
    return Object.fromEntries(entries);
}
export function hasAllRequiredOutputHashes(unit) {
    return unit.outputRefs.every((outputRef) => unit.outputHashes[outputRef] !== null);
}
export function isTrustedLedgerUnit(unit) {
    return (unit.status === "completed" &&
        unit.trustStatus === "trusted" &&
        hasAllRequiredOutputHashes(unit));
}
export function firstUntrustedRequiredUnit(ledger) {
    return ledger.units.find((unit) => !isTrustedLedgerUnit(unit)) ?? null;
}
export function normalizeLedgerRefs(refs) {
    return [...new Set(refs.filter((ref) => typeof ref === "string" && ref.length > 0))]
        .sort();
}
export function buildLedgerTrust(args) {
    if (!args.upstreamTrusted) {
        return {
            trustStatus: "blocked_by_upstream",
            trustReason: "A required upstream unit is not trusted.",
        };
    }
    if (args.status === "completed") {
        const missingOutputRefs = args.outputRefs.filter((outputRef) => args.outputHashes[outputRef] === null);
        if (missingOutputRefs.length > 0) {
            return {
                trustStatus: "untrusted",
                trustReason: `Completed unit is missing required output refs: ${missingOutputRefs.join(", ")}.`,
            };
        }
        return {
            trustStatus: "trusted",
            trustReason: "Unit completed and required output refs are present.",
        };
    }
    if (args.status === "failed") {
        return {
            trustStatus: "untrusted",
            trustReason: args.lastFailureMessage?.trim() ||
                "Unit failed before producing a trusted output.",
        };
    }
    if (args.status === "skipped") {
        return {
            trustStatus: "untrusted",
            trustReason: "Unit was skipped and did not produce a trusted output.",
        };
    }
    if (args.status === "missing") {
        return {
            trustStatus: "untrusted",
            trustReason: "Required unit output is missing.",
        };
    }
    if (args.status === "not_reached") {
        return {
            trustStatus: "blocked_by_upstream",
            trustReason: "Unit was not reached because upstream execution did not complete.",
        };
    }
    return {
        trustStatus: "untrusted",
        trustReason: "Unit is planned but has not completed.",
    };
}
