"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.readExecutableCommands = readExecutableCommands;
exports.runGit = runGit;
exports.baselineResult = baselineResult;
exports.resolveTaskPair = resolveTaskPair;
exports.assertResumeIdentity = assertResumeIdentity;
exports.requireActor = requireActor;
exports.requireCaptureTime = requireCaptureTime;
exports.readBoundedGitStatus = readBoundedGitStatus;
exports.nullableScalarValue = nullableScalarValue;
exports.assertIdentity = assertIdentity;
exports.hashCanonical = hashCanonical;
exports.quote = quote;
exports.unique = unique;
exports.sameValues = sameValues;
exports.sameAdoptions = sameAdoptions;
exports.sameAcceptedPredecessorPaths = sameAcceptedPredecessorPaths;
exports.toSnakeCase = toSnakeCase;
const node_child_process_1 = require("node:child_process");
const node_crypto_1 = require("node:crypto");
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const errors_1 = require("../../errors");
const command_write_summary_1 = require("../../license/command-write-summary");
const paths_1 = require("../../paths");
const canonical_write_target_1 = require("../../paths/canonical-write-target");
const task_lifecycle_1 = require("../task-lifecycle");
const task_lifecycle_timestamps_1 = require("../task-lifecycle-timestamps");
const contracts_1 = require("./contracts");
function readExecutableCommands(text) {
    const commands = [];
    for (const match of text.matchAll(/`([^`\n]+)`/g)) {
        const command = match[1].trim();
        if (/^(?:node|pnpm|npm|yarn|bun|deno|cargo|go|pytest|python\d*|git\s+diff\s+--check)\b/.test(command)) {
            commands.push(command);
        }
    }
    return unique(commands);
}
function runGit(repositoryRoot, args) {
    const result = (0, node_child_process_1.spawnSync)("git", ["-C", repositoryRoot, ...args], {
        encoding: "utf8",
        stdio: ["ignore", "pipe", "ignore"],
        timeout: 5_000,
        maxBuffer: 2_000_000
    });
    return result.status === 0 && typeof result.stdout === "string" ? result.stdout.trim() : null;
}
function baselineResult(options) {
    const changed = options.changedPaths.length > 0;
    return {
        taskDefinitionPath: options.taskDefinitionPath,
        implementationSummaryPath: options.implementationSummaryPath,
        action: options.action,
        changed,
        writeApplied: changed,
        baseline: options.baseline,
        intendedPaths: [...options.intendedPaths],
        changedPaths: [...options.changedPaths],
        writeOutcome: options.writeOutcome,
        transactionId: options.transactionId,
        evidenceGaps: [...options.evidenceGaps],
        commandWriteSummary: (0, command_write_summary_1.normalizeCommandWriteSummary)({
            commandFamily: "metadata_update",
            primaryOutputArtifacts: [...options.intendedPaths],
            updatedArtifacts: (options.intendedPaths.length === 0
                ? [options.implementationSummaryPath]
                : options.intendedPaths).map((artifactPath) => ({
                path: artifactPath,
                action: options.changedPaths.includes(artifactPath) ? "changed" : "kept",
                reason: options.changedPaths.includes(artifactPath) ? "provided_material" : "no_write"
            }))
        })
    };
}
function resolveTaskPair(repositoryRoot, taskDefinitionPath) {
    const root = node_fs_1.default.realpathSync(node_path_1.default.resolve(repositoryRoot));
    const parsed = (0, paths_1.parseRepositoryRelativePath)(taskDefinitionPath);
    if (parsed.segments.at(-1) !== "task-definition.md") {
        throw (0, errors_1.createUsageError)("Task baseline paths must end in task-definition.md.");
    }
    const task = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(root, parsed.normalizedPath);
    const summary = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(root, [...parsed.segments.slice(0, -1), "implementation-summary.md"].join("/"));
    if (!task.exists || !summary.exists) {
        throw (0, errors_1.createUsageError)("Task baseline requires both task-definition.md and implementation-summary.md.");
    }
    return { repositoryRoot: root, task, summary };
}
function assertResumeIdentity(baseline, options, artifactPath) {
    if (baseline.taskCycleId !== options.taskCycleId || baseline.checkpointId !== options.checkpointId) {
        throw (0, errors_1.createUsageError)(`Resume identity does not match stored baseline '${baseline.baselineId}' at '${artifactPath}'.`, [
            `Stored task-cycle ID: ${baseline.taskCycleId}`,
            `Stored checkpoint ID: ${baseline.checkpointId}`,
            "No files were written."
        ]);
    }
}
function requireActor(value) {
    if (value === undefined || value.trim() === "") {
        throw (0, errors_1.createUsageError)("New attempt-owned baseline capture requires --captured-by <actor>.");
    }
    return value.trim();
}
function requireCaptureTime(value, openedAt) {
    if (value === undefined || !(0, task_lifecycle_1.isTaskLifecycleTimestamp)(value)) {
        throw (0, errors_1.createUsageError)("New attempt-owned baseline capture requires a valid --captured-at timestamp.");
    }
    (0, task_lifecycle_timestamps_1.requireObservedLifecycleTimestamp)({
        value,
        field: "captured_at",
        label: "Baseline captured_at"
    });
    if (openedAt !== null && Date.parse(value) < Date.parse(openedAt)) {
        throw (0, errors_1.createUsageError)("Baseline captured_at cannot precede the current attempt opened_at timestamp.");
    }
    return value;
}
function readBoundedGitStatus(repositoryRoot) {
    const result = (0, node_child_process_1.spawnSync)("git", [
        "-C", repositoryRoot,
        "status", "--porcelain=v1", "-z", "--untracked-files=all",
        "--", ".", ":(exclude).day-shift/runs"
    ], {
        stdio: ["ignore", "pipe", "ignore"],
        timeout: 5_000,
        maxBuffer: contracts_1.MAX_STATUS_BYTES
    });
    if (result.status !== 0 || !Buffer.isBuffer(result.stdout)) {
        throw (0, errors_1.createUsageError)("Unable to capture bounded Git working-tree status for task baseline.");
    }
    const paths = result.stdout.toString("utf8").split("\0").filter((entry) => entry !== "");
    if (paths.length > contracts_1.MAX_STATUS_PATHS) {
        throw (0, errors_1.createUsageError)(`Git status exceeds the bounded ${contracts_1.MAX_STATUS_PATHS}-path baseline limit.`);
    }
    return result.stdout;
}
function nullableScalarValue(value) {
    return value === undefined || value === "" || value === "null" ? null : value;
}
function assertIdentity(label, value) {
    if (!contracts_1.IDENTITY_PATTERN.test(value)) {
        throw (0, errors_1.createUsageError)(`Invalid ${label} identity '${value}'.`, ["Use 3-128 printable identity characters: letters, digits, dot, underscore, colon, or hyphen."]);
    }
}
function hashCanonical(value) {
    return `sha256:${(0, node_crypto_1.createHash)("sha256").update(JSON.stringify(value)).digest("hex")}`;
}
function quote(value) {
    return JSON.stringify(value);
}
function unique(values) {
    return [...new Set(values)];
}
function sameValues(left, right) {
    return left.length === right.length && left.every((value, index) => value === right[index]);
}
function sameAdoptions(left, right) {
    return left.length === right.length
        && left.every((entry, index) => entry.path === right[index]?.path && entry.rationale === right[index]?.rationale);
}
function sameAcceptedPredecessorPaths(left, right) {
    return JSON.stringify(left) === JSON.stringify(right);
}
function toSnakeCase(value) {
    return value.replace(/[A-Z]/g, (character) => `_${character.toLowerCase()}`);
}
