// SF Extension — Operator-invoked reconcile remediation
//
// The DB-driven reconcile path (state-db.js: reconcileSliceTasks) refuses to
// silently import on-disk SUMMARY metadata when the DB row says `pending` —
// that safety check exists so an autonomous run cannot accidentally promote
// itself to "complete" by writing a SUMMARY without a real DB transition.
//
// But the refusal leaves operators with no path forward when the drift is
// real (autonomous run completed a task but the DB write was lost, or the
// state was hand-edited). This module is the explicit remediation surface:
// parse the on-disk SUMMARY, validate it, and write its fields into the DB
// row — operator action only, never auto-triggered by reconcile.

import { existsSync, readFileSync } from "node:fs";
import { isValidTaskSummary, parseSummary } from "./files.js";
import { resolveTaskFile } from "./paths.js";
import { getTask, isDbAvailable, setTaskSummaryFields } from "./sf-db.js";

/**
 * Apply an on-disk task SUMMARY.md to the DB row.
 *
 * Returns one of:
 *   { ok: true,  applied: <fields-applied> }
 *   { ok: false, reason: <code>, detail?: <string> }
 *
 * Reason codes (none throw — operator tooling needs structured outcomes):
 *   `db-unavailable`  — sf.db is not open / not initialized
 *   `summary-missing` — no SUMMARY.md at the resolved task path
 *   `summary-invalid` — file exists but isValidTaskSummary rejected it
 *   `task-not-in-db`  — no DB row for milestoneId/sliceId/taskId
 *   `already-done`    — DB row is already in a terminal status; no-op
 */
export function reconcileTaskFromSummary(
	basePath,
	milestoneId,
	sliceId,
	taskId,
) {
	if (!isDbAvailable()) {
		return { ok: false, reason: "db-unavailable" };
	}

	const summaryPath = resolveTaskFile(
		basePath,
		milestoneId,
		sliceId,
		taskId,
		"SUMMARY",
	);
	if (!summaryPath || !existsSync(summaryPath)) {
		return { ok: false, reason: "summary-missing" };
	}

	const content = readFileSync(summaryPath, "utf-8");
	if (!isValidTaskSummary(content)) {
		return {
			ok: false,
			reason: "summary-invalid",
			detail: `${summaryPath} exists but failed isValidTaskSummary`,
		};
	}

	const existing = getTask(milestoneId, sliceId, taskId);
	if (!existing) {
		return { ok: false, reason: "task-not-in-db" };
	}
	if (existing.status === "complete" || existing.status === "done") {
		return { ok: false, reason: "already-done", detail: existing.status };
	}

	const parsed = parseSummary(content);
	const fm = parsed.frontmatter ?? {};

	const fields = {
		status: "complete",
		completedAt: fm.completed_at || new Date().toISOString(),
		verificationResult: fm.verification_result || "passed",
		blockerDiscovered: !!fm.blocker_discovered,
		keyFiles: Array.isArray(fm.key_files) ? fm.key_files : [],
		keyDecisions: Array.isArray(fm.key_decisions) ? fm.key_decisions : [],
		summaryMd: content,
	};

	setTaskSummaryFields(milestoneId, sliceId, taskId, fields);

	return { ok: true, applied: fields };
}
