import path from "node:path";
import { appendEvent } from "../observability/index.js";
import { runDir } from "../run-state/index.js";
import { LAB_REPRESENTATIVE_AGENT } from "../../agents/identity.js";
import { createId, nowIso, readJsonFile, withFileLock, writeJsonFile } from "../../shared/index.js";
import { assertSubplanExecutionReady, assertSubplanTransitionAllowed, nextStatusForVerdict } from "./state-machine.js";
export function subplansPath(store, runId) {
    return path.join(runDir(store, runId), "subplans.json");
}
export async function listSubplans(store, runId) {
    return ((await readJsonFile(subplansPath(store, runId))) ?? []).map(normalizeSubplan);
}
export async function createSubplan(store, runId, input) {
    const file = subplansPath(store, runId);
    const subplan = await withFileLock(file, async () => {
        const subplans = ((await readJsonFile(file)) ?? []).map(normalizeSubplan);
        const timestamp = nowIso();
        const writePaths = input.write_paths ?? [];
        const next = {
            subplan_id: createId("subplan"),
            title: input.title,
            objective: input.objective,
            owner_member: input.owner_member,
            verifier_member: input.verifier_member,
            status: "planned",
            required_for_final: input.required_for_final ?? true,
            read_paths: input.read_paths ?? [],
            write_paths: writePaths,
            workspace_strategy: input.workspace_strategy ?? (writePaths.length > 0 ? "exclusive_lease" : "serialized"),
            workspace_conflict_policy: input.workspace_conflict_policy ?? "meeting",
            worktree_path: input.worktree_path,
            merge_owner_member: input.merge_owner_member,
            lease_ids: [],
            diff_refs: [],
            evidence_refs: input.evidence_refs ?? [],
            created_at: timestamp,
            updated_at: timestamp,
            transitions: [],
        };
        await writeJsonFile(file, [...subplans, next]);
        return next;
    });
    await appendEvent(store, runId, {
        type: "subplan_created",
        actor: input.actor ?? store.config.default_run_agent ?? LAB_REPRESENTATIVE_AGENT,
        session_id: input.sessionId,
        summary: `${subplan.subplan_id}: ${subplan.title}`,
        metadata: { subplan },
    });
    return subplan;
}
export async function transitionSubplan(store, runId, subplanId, input) {
    const updated = await updateSubplan(store, runId, subplanId, (subplan) => {
        assertSubplanTransitionAllowed(subplan.status, input.to);
        if (input.to === "executing")
            assertSubplanExecutionReady(subplan, input.active_workspace_leases ?? []);
        const timestamp = nowIso();
        const transition = {
            from: subplan.status,
            to: input.to,
            at: timestamp,
            actor: input.actor,
            summary: input.summary,
            evidence_refs: input.evidence_refs ?? [],
        };
        return {
            ...subplan,
            status: input.to,
            updated_at: timestamp,
            evidence_refs: unique([...subplan.evidence_refs, ...transition.evidence_refs]),
            transitions: [...subplan.transitions, transition],
        };
    });
    await appendEvent(store, runId, {
        type: "subplan_transitioned",
        actor: input.actor ?? store.config.default_run_agent ?? LAB_REPRESENTATIVE_AGENT,
        session_id: input.sessionId,
        summary: `${subplanId}: ${updated.transitions.at(-1)?.from} -> ${updated.status}`,
        metadata: { subplan_id: subplanId, status: updated.status, transition: updated.transitions.at(-1) },
    });
    return updated;
}
export async function verifySubplan(store, runId, subplanId, input) {
    const nextStatus = nextStatusForVerdict(input.verdict);
    const updated = await updateSubplan(store, runId, subplanId, (subplan) => {
        assertSubplanTransitionAllowed(subplan.status, nextStatus);
        const timestamp = nowIso();
        const transition = {
            from: subplan.status,
            to: nextStatus,
            at: timestamp,
            actor: input.actor,
            summary: input.summary,
            evidence_refs: input.evidence_refs ?? [],
        };
        return {
            ...subplan,
            status: nextStatus,
            updated_at: timestamp,
            evidence_refs: unique([...subplan.evidence_refs, ...transition.evidence_refs]),
            transitions: [...subplan.transitions, transition],
            latest_verdict: {
                verdict: input.verdict,
                summary: input.summary,
                evidence_refs: input.evidence_refs ?? [],
                at: timestamp,
                actor: input.actor,
            },
        };
    });
    await appendEvent(store, runId, {
        type: "subplan_verified",
        actor: input.actor ?? store.config.default_run_agent ?? LAB_REPRESENTATIVE_AGENT,
        session_id: input.sessionId,
        summary: `${subplanId}: ${input.verdict}`,
        metadata: { subplan_id: subplanId, verdict: input.verdict, status: updated.status, evidence_refs: input.evidence_refs ?? [] },
    });
    return updated;
}
export async function requiredSubplansBlockingFinal(store, runId) {
    const subplans = await listSubplans(store, runId);
    return subplans.filter((subplan) => subplan.required_for_final && subplan.status !== "accepted" && subplan.status !== "cancelled");
}
export async function bindSubplanWorkspaceLease(store, runId, subplanId, leaseId, input = {}) {
    const updated = await updateSubplan(store, runId, subplanId, (subplan) => ({
        ...subplan,
        lease_ids: unique([...subplan.lease_ids, leaseId]),
        updated_at: nowIso(),
    }));
    await appendEvent(store, runId, {
        type: "subplan_workspace_lease_bound",
        actor: input.actor ?? store.config.default_run_agent ?? LAB_REPRESENTATIVE_AGENT,
        session_id: input.sessionId,
        summary: `${subplanId}: lease ${leaseId}`,
        metadata: { subplan_id: subplanId, lease_id: leaseId },
    });
    return updated;
}
export async function attachSubplanDiffRef(store, runId, subplanId, diffRef, input = {}) {
    const updated = await updateSubplan(store, runId, subplanId, (subplan) => ({
        ...subplan,
        diff_refs: unique([...subplan.diff_refs, diffRef]),
        evidence_refs: unique([...subplan.evidence_refs, diffRef]),
        updated_at: nowIso(),
    }));
    await appendEvent(store, runId, {
        type: "subplan_workspace_diff_attached",
        actor: input.actor ?? store.config.default_run_agent ?? LAB_REPRESENTATIVE_AGENT,
        session_id: input.sessionId,
        summary: `${subplanId}: diff ${diffRef}`,
        metadata: { subplan_id: subplanId, diff_ref: diffRef },
    });
    return updated;
}
async function updateSubplan(store, runId, subplanId, update) {
    const file = subplansPath(store, runId);
    return withFileLock(file, async () => {
        const subplans = ((await readJsonFile(file)) ?? []).map(normalizeSubplan);
        let updated;
        const next = subplans.map((subplan) => {
            if (subplan.subplan_id !== subplanId)
                return subplan;
            updated = update(subplan);
            return updated;
        });
        if (!updated)
            throw new Error(`subplan not found: ${subplanId}`);
        await writeJsonFile(file, next);
        return updated;
    });
}
function normalizeSubplan(subplan) {
    const writePaths = subplan.write_paths ?? [];
    return {
        ...subplan,
        read_paths: subplan.read_paths ?? [],
        write_paths: writePaths,
        workspace_strategy: subplan.workspace_strategy ?? (writePaths.length > 0 ? "exclusive_lease" : "serialized"),
        workspace_conflict_policy: subplan.workspace_conflict_policy ?? "meeting",
        worktree_path: subplan.worktree_path,
        merge_owner_member: subplan.merge_owner_member,
        lease_ids: subplan.lease_ids ?? [],
        diff_refs: subplan.diff_refs ?? [],
        evidence_refs: subplan.evidence_refs ?? [],
        transitions: subplan.transitions ?? [],
    };
}
function unique(values) {
    return [...new Set(values.filter(Boolean))];
}
//# sourceMappingURL=store.js.map