/**
 * reopen-task handler — the core operation behind nerf_task_reopen.
 *
 * Resets a completed task back to "pending" so it can be re-done
 * without manual SQL surgery. The parent slice and milestone must
 * still be open (not complete) — you cannot reopen tasks inside a
 * closed slice.
 */
// NERF — reopen-task tool handler
// Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
import { getMilestone, getSlice, getTask, updateTaskStatus, transaction, } from "../nerf-db.js";
import { invalidateStateCache } from "../state.js";
import { isClosedStatus } from "../status-guards.js";
import { renderAllProjections } from "../workflow-projections.js";
import { writeManifest } from "../workflow-manifest.js";
import { appendEvent } from "../workflow-events.js";
export async function handleReopenTask(params, basePath) {
    // ── Validate required fields ────────────────────────────────────────────
    if (!params.taskId || typeof params.taskId !== "string" || params.taskId.trim() === "") {
        return { error: "taskId is required and must be a non-empty string" };
    }
    if (!params.sliceId || typeof params.sliceId !== "string" || params.sliceId.trim() === "") {
        return { error: "sliceId is required and must be a non-empty string" };
    }
    if (!params.milestoneId || typeof params.milestoneId !== "string" || params.milestoneId.trim() === "") {
        return { error: "milestoneId is required and must be a non-empty string" };
    }
    // ── Guards + DB write inside a single transaction (prevents TOCTOU) ────
    let guardError = null;
    transaction(() => {
        const milestone = getMilestone(params.milestoneId);
        if (!milestone) {
            guardError = `milestone not found: ${params.milestoneId}`;
            return;
        }
        if (isClosedStatus(milestone.status)) {
            guardError = `cannot reopen task in a closed milestone: ${params.milestoneId} (status: ${milestone.status})`;
            return;
        }
        const slice = getSlice(params.milestoneId, params.sliceId);
        if (!slice) {
            guardError = `slice not found: ${params.milestoneId}/${params.sliceId}`;
            return;
        }
        if (isClosedStatus(slice.status)) {
            guardError = `cannot reopen task in a closed slice: ${params.sliceId} (status: ${slice.status}) — use nerf_slice_reopen first`;
            return;
        }
        const task = getTask(params.milestoneId, params.sliceId, params.taskId);
        if (!task) {
            guardError = `task not found: ${params.milestoneId}/${params.sliceId}/${params.taskId}`;
            return;
        }
        if (!isClosedStatus(task.status)) {
            guardError = `task ${params.taskId} is not complete (status: ${task.status}) — nothing to reopen`;
            return;
        }
        updateTaskStatus(params.milestoneId, params.sliceId, params.taskId, "pending");
    });
    if (guardError) {
        return { error: guardError };
    }
    // ── Invalidate caches ────────────────────────────────────────────────────
    invalidateStateCache();
    // ── Post-mutation hook ───────────────────────────────────────────────────
    try {
        await renderAllProjections(basePath, params.milestoneId);
        writeManifest(basePath);
        appendEvent(basePath, {
            cmd: "reopen-task",
            params: {
                milestoneId: params.milestoneId,
                sliceId: params.sliceId,
                taskId: params.taskId,
                reason: params.reason ?? null,
            },
            ts: new Date().toISOString(),
            actor: "agent",
            actor_name: params.actorName,
            trigger_reason: params.triggerReason,
        });
    }
    catch (hookErr) {
        process.stderr.write(`nerf: reopen-task post-mutation hook warning: ${hookErr.message}\n`);
    }
    return {
        milestoneId: params.milestoneId,
        sliceId: params.sliceId,
        taskId: params.taskId,
    };
}
