"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createTaskWaiverCommand = createTaskWaiverCommand;
exports.createTaskRetryAuthorizeCommand = createTaskRetryAuthorizeCommand;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const errors_1 = require("../../../lib/errors");
const output_1 = require("../../../lib/output");
const task_waivers_1 = require("../../../lib/planning/task-waivers");
const task_lifecycle_transitions_1 = require("../../../lib/planning/task-lifecycle-transitions");
const task_lifecycle_timestamps_1 = require("../../../lib/planning/task-lifecycle-timestamps");
const runtime_contract_1 = require("../../../lib/runtime/runtime-contract");
const global_format_1 = require("../global-format");
async function createTaskWaiverCommand() {
    const { Command } = await import('commander');
    const command = new Command('waiver');
    command.description('Record or revoke one typed, auditable task waiver through pair-guarded preview/apply writes.');
    command
        .command('record')
        .description('Preview or record one append-only task waiver identity.')
        .requiredOption('--task-definition <path>', 'Repository-relative canonical task-definition.md path.')
        .requiredOption('--waiver-id <identity>', 'Stable append-only waiver identity.')
        .requiredOption('--waiver-type <value>', 'readiness, validation, review, scope_deviation, or administrative.')
        .requiredOption('--subject-id <identity>', 'Exact subject identity this waiver may satisfy.')
        .option('--attempt-id <identity>', 'Owning current attempt; omit only for readiness transition evidence.')
        .requiredOption('--reason <text>', 'Concrete waiver reason.')
        .requiredOption('--recorded-by <actor>', 'Waiver actor.')
        .requiredOption('--recorded-at <timestamp>', 'ISO-8601 record time with explicit timezone.')
        .option('--expires-at <timestamp>', 'Optional exclusive expiry time.')
        .option('--authority-reference <value>', 'Authority reference; required for readiness, review, and administrative waivers.')
        .option('--dry-run', 'Preview pair preconditions and exact evidence without mutation.')
        .action((_, instance) => runWaiverRecord(instance));
    command
        .command('revoke')
        .description('Preview or revoke one existing active waiver while preserving its original audit.')
        .requiredOption('--task-definition <path>', 'Repository-relative canonical task-definition.md path.')
        .requiredOption('--waiver-id <identity>', 'Existing active waiver identity.')
        .requiredOption('--revoked-by <actor>', 'Revocation actor.')
        .requiredOption('--revoked-at <timestamp>', 'ISO-8601 revocation time with explicit timezone.')
        .requiredOption('--reason <text>', 'Concrete revocation reason.')
        .option('--dry-run', 'Preview pair preconditions and exact evidence without mutation.')
        .action((_, instance) => runWaiverRevoke(instance));
    return command;
}
async function createTaskRetryAuthorizeCommand() {
    const { Command } = await import('commander');
    const command = new Command('retry-authorize');
    command
        .description('Atomically bind a clean readiness review and append its changes-requested successor attempt.')
        .requiredOption('--task-definition <path>', 'Repository-relative canonical task-definition.md path reset to needs_more_evidence.')
        .requiredOption('--review-result <path>', 'Repository-local complete readiness-review JSON result for the reset task bytes.')
        .requiredOption('--attempt-id <identity>', 'Stable successor attempt identity.')
        .requiredOption('--opened-at <timestamp>', 'ISO-8601 successor opening time with explicit timezone.')
        .option('--dry-run', 'Preview the atomic pair transition without mutation.')
        .action((_, instance) => {
        const context = outputContext(instance);
        const options = instance.opts();
        let preview;
        try {
            preview = (0, task_lifecycle_transitions_1.previewTaskRetryAuthorizationSync)({
                repositoryRoot: context.repository.root,
                taskDefinitionPath: options.taskDefinition,
                reviewResult: readReviewResult(context.repository.root, options.reviewResult),
                attemptId: options.attemptId,
                openedAt: options.openedAt,
            });
        }
        catch (error) {
            throw mutationError(error, 'No readiness authorization or successor attempt was written.');
        }
        const result = options.dryRun === true ? preview : (0, task_lifecycle_transitions_1.applyTaskLifecycleTransitionSync)(preview);
        ensureOutcome(result.writeOutcome, result.failure, result.recoveryPath, result.conflicts);
        (0, output_1.emitSuccess)({
            command: 'task retry-authorize',
            format: context.format,
            text: [
                'Task retry authorization',
                '',
                `Task definition: ${result.taskDefinitionPath}`,
                `Successor attempt: ${options.attemptId}`,
                `Write outcome: ${result.writeOutcome}`,
                `Changed paths: ${result.changedPaths.length}`,
            ].join('\n'),
            data: {
                ...result,
                repositoryRoot: context.repository.root,
                detectionSource: context.repository.detectionSource,
            },
        });
    });
    return command;
}
function runWaiverRecord(instance) {
    const context = outputContext(instance);
    const options = instance.opts();
    let preview;
    try {
        preview = (0, task_waivers_1.previewTaskWaiverRecordSync)({
            repositoryRoot: context.repository.root,
            taskDefinitionPath: options.taskDefinition,
            waiverId: options.waiverId,
            waiverType: options.waiverType,
            subjectId: options.subjectId,
            attemptId: options.attemptId,
            reason: options.reason,
            recordedBy: options.recordedBy,
            recordedAt: options.recordedAt,
            expiresAt: options.expiresAt,
            authorityReference: options.authorityReference,
        });
    }
    catch (error) {
        throw mutationError(error, 'No waiver evidence was written.');
    }
    const result = options.dryRun === true ? preview : (0, task_waivers_1.applyTaskWaiverMutationSync)(preview);
    ensureOutcome(result.writeOutcome, result.failure, result.recoveryPath, result.conflicts);
    emitWaiverResult('task waiver record', context, result);
}
function runWaiverRevoke(instance) {
    const context = outputContext(instance);
    const options = instance.opts();
    let preview;
    try {
        preview = (0, task_waivers_1.previewTaskWaiverRevokeSync)({
            repositoryRoot: context.repository.root,
            taskDefinitionPath: options.taskDefinition,
            waiverId: options.waiverId,
            revokedBy: options.revokedBy,
            revokedAt: options.revokedAt,
            reason: options.reason,
        });
    }
    catch (error) {
        throw mutationError(error, 'No waiver evidence was changed.');
    }
    const result = options.dryRun === true ? preview : (0, task_waivers_1.applyTaskWaiverMutationSync)(preview);
    ensureOutcome(result.writeOutcome, result.failure, result.recoveryPath, result.conflicts);
    emitWaiverResult('task waiver revoke', context, result);
}
function emitWaiverResult(command, context, result) {
    (0, output_1.emitSuccess)({
        command,
        format: context.format,
        text: [
            'Task waiver mutation',
            '',
            `Task definition: ${result.taskDefinitionPath}`,
            `Waiver ID: ${result.waiver.waiverId}`,
            `Waiver type: ${result.waiver.waiverType}`,
            `Status: ${result.waiver.status}`,
            `Write outcome: ${result.writeOutcome}`,
            `Changed paths: ${result.changedPaths.length}`,
        ].join('\n'),
        data: { ...result, repositoryRoot: context.repository.root, detectionSource: context.repository.detectionSource },
    });
}
function outputContext(instance) {
    let root = instance;
    while (root?.parent !== null && root?.parent !== undefined)
        root = root.parent;
    const format = (0, output_1.resolveOutputFormat)(root?.opts?.().format ?? (0, global_format_1.getGlobalFormat)(instance));
    if (format === null)
        throw (0, errors_1.createUsageError)('Output format must be one of: text, json.');
    const repository = (0, runtime_contract_1.createRepositoryContext)((0, runtime_contract_1.detectRepositoryRoot)(), false);
    return { format, repository };
}
function ensureOutcome(outcome, failure, recoveryPath, conflicts) {
    if (outcome === 'previewed' || outcome === 'committed')
        return;
    throw (0, errors_1.createUsageError)(`Task mutation ended with '${outcome}'.`, [
        ...(failure === null ? [] : [failure]),
        ...(recoveryPath === null ? [] : [`Recovery record: ${recoveryPath}`]),
        ...conflicts.map((entry) => `${entry.path}: ${entry.guidance}`),
    ]);
}
function mutationError(error, noWrite) {
    if (error instanceof task_lifecycle_timestamps_1.TaskLifecycleTimestampValidationError)
        return error;
    return (0, errors_1.createUsageError)(error instanceof Error ? error.message : String(error), [noWrite]);
}
function readReviewResult(repositoryRoot, requestedPath) {
    const root = node_fs_1.default.realpathSync(repositoryRoot);
    const resolved = node_fs_1.default.realpathSync(node_path_1.default.resolve(root, requestedPath));
    const relative = node_path_1.default.relative(root, resolved);
    if (relative === '' || relative.startsWith('..') || node_path_1.default.isAbsolute(relative) || !node_fs_1.default.statSync(resolved).isFile()) {
        throw new TypeError('--review-result must resolve to a regular file inside the repository.');
    }
    const parsed = JSON.parse(node_fs_1.default.readFileSync(resolved, 'utf8'));
    if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed))
        throw new TypeError('Review result must be a JSON object.');
    const record = parsed;
    const data = record.data !== null && typeof record.data === 'object' && !Array.isArray(record.data)
        ? record.data
        : null;
    const result = data?.reviewResult !== null && typeof data?.reviewResult === 'object' && !Array.isArray(data.reviewResult)
        ? data.reviewResult
        : (data ?? record);
    return result;
}
