import { createRandomId } from "@best-agent/foundation";
export class LocalPlanStore {
    #threads;
    constructor(threads) {
        this.#threads = threads;
    }
    async getProjection(threadId) {
        const state = await this.#threads.getPlanState(threadId);
        return state?.plan ?? null;
    }
    async saveProjection(plan) {
        const previous = await this.#threads.getPlanState(plan.threadId);
        const saved = await this.#threads.savePlanState({
            nodeContracts: collectNodeContracts(previous),
            plan,
        });
        return saved.plan;
    }
    async updateProjectionTodos(threadId, todos) {
        const existing = await this.#requirePlanState(threadId);
        const nextPlan = {
            ...existing.plan,
            approvedRevision: undefined,
            graphRevision: existing.plan.graphRevision + 1,
            rejectedRevision: undefined,
            todos,
            updatedAt: now(),
        };
        const saved = await this.#threads.savePlanState({
            nodeContracts: collectNodeContracts(existing),
            plan: nextPlan,
        });
        return saved.plan;
    }
    async updateProjectionStatus(threadId, status) {
        const existing = await this.#requirePlanState(threadId);
        const nextPlan = {
            ...existing.plan,
            approvedRevision: status === "approved" ? existing.plan.graphRevision : existing.plan.approvedRevision,
            rejectedRevision: status === "rejected" ? existing.plan.graphRevision : existing.plan.rejectedRevision,
            status,
            updatedAt: now(),
        };
        const saved = await this.#threads.savePlanState({
            nodeContracts: collectNodeContracts(existing),
            plan: nextPlan,
        });
        return saved.plan;
    }
    async exportProjection(threadId) {
        const state = await this.#threads.getPlanState(threadId);
        if (!state) {
            return null;
        }
        return renderPlanProjection(state.plan);
    }
    async cloneProjection(sourceThreadId, targetThreadId) {
        const existing = await this.#threads.getPlanState(sourceThreadId);
        if (!existing) {
            return null;
        }
        const clonedPlan = {
            ...existing.plan,
            approvedRevision: undefined,
            graphId: createRandomId("graph"),
            graphRevision: 1,
            rejectedRevision: undefined,
            threadId: targetThreadId,
            updatedAt: now(),
        };
        const saved = await this.#threads.savePlanState({
            nodeContracts: [],
            plan: clonedPlan,
        });
        return saved.plan;
    }
    async #requirePlanState(threadId) {
        const existing = await this.#threads.getPlanState(threadId);
        if (!existing) {
            throw new Error(`Plan projection for thread ${threadId} not found`);
        }
        return existing;
    }
}
export function renderPlanProjection(plan) {
    const lines = [];
    lines.push(`# ${plan.title}`);
    lines.push("");
    lines.push(`Status: ${plan.status}`);
    lines.push("");
    lines.push("## Summary");
    lines.push(plan.summary || "(empty)");
    lines.push("");
    lines.push("## Todos");
    if (plan.todos.length === 0) {
        lines.push("- (none)");
    }
    else {
        for (const todo of plan.todos) {
            lines.push(renderPlanTodo(todo));
        }
    }
    lines.push("");
    lines.push("## Risks");
    lines.push(...renderList(plan.risks));
    lines.push("");
    lines.push("## Open Questions");
    lines.push(...renderList(plan.openQuestions));
    lines.push("");
    lines.push("## Acceptance Criteria");
    lines.push(...renderList(plan.acceptanceCriteria));
    lines.push("");
    lines.push("## Affected Paths");
    lines.push(...renderList(plan.affectedPaths));
    lines.push("");
    lines.push("## Evidence");
    lines.push(...renderList(plan.evidenceRefs));
    return lines.join("\n").trim();
}
function collectNodeContracts(state) {
    if (!state) {
        return undefined;
    }
    const contracts = state.nodes.flatMap((node) => (node.contract ? [node.contract] : []));
    return contracts.length > 0 ? contracts : undefined;
}
function renderList(values) {
    if (values.length === 0) {
        return ["- (none)"];
    }
    return values.map((value) => `- ${value}`);
}
function renderPlanTodo(todo) {
    const checkbox = todo.status === "done" ? "[x]" : "[ ]";
    const suffix = describePlanTodoStatus(todo.status);
    return suffix ? `- ${checkbox} ${todo.content} (${suffix})` : `- ${checkbox} ${todo.content}`;
}
function describePlanTodoStatus(status) {
    switch (status) {
        case "in_progress":
            return "in progress";
        case "blocked":
            return "blocked";
        case "cancelled":
            return "cancelled";
        default:
            return undefined;
    }
}
function now() {
    return new Date().toISOString();
}
//# sourceMappingURL=plan-store.js.map