// engine/spec-versioning/brancher.ts — Create, list, and delete spec branches
import { readFile, writeFile, mkdir, unlink } from 'node:fs/promises';
import { join } from 'node:path';
import { existsSync } from 'node:fs';
import { getVersionsDir, getLatestVersionTag } from './version-store.js';
const BRANCHES_SUBDIR = 'branches';
/** Build the path to a branch JSON file. */
function getBranchFilePath(dataDir, specId, branchName) {
    return join(getVersionsDir(dataDir, specId), BRANCHES_SUBDIR, `${branchName}.json`);
}
/** Build the branches directory for a spec. */
function getBranchesDir(dataDir, specId) {
    return join(getVersionsDir(dataDir, specId), BRANCHES_SUBDIR);
}
/** Validate branch name: lowercase kebab-case, non-empty. */
export function isValidBranchName(name) {
    return /^[a-z][a-z0-9-]*$/.test(name) && name.length <= 100;
}
/** Load a branch. Returns null if not found. */
export async function loadBranch(dataDir, specId, branchName) {
    const filePath = getBranchFilePath(dataDir, specId, branchName);
    try {
        const raw = await readFile(filePath, 'utf-8');
        return JSON.parse(raw);
    }
    catch {
        return null;
    }
}
/** Persist a branch to disk. Creates directories as needed. */
async function saveBranch(dataDir, branch) {
    const dir = getBranchesDir(dataDir, branch.specId);
    if (!existsSync(dir)) {
        await mkdir(dir, { recursive: true });
    }
    const filePath = getBranchFilePath(dataDir, branch.specId, branch.name);
    await writeFile(filePath, JSON.stringify(branch, null, 2), 'utf-8');
}
/**
 * Create a new spec branch.
 * Throws if branch name is invalid, already exists, or fromVersion is not found.
 */
export async function createBranch(dataDir, input) {
    const { specId, branchName, content } = input;
    if (!isValidBranchName(branchName)) {
        throw new Error(`Invalid branch name "${branchName}". Use lowercase kebab-case (e.g., "auth-refactor").`);
    }
    const existing = await loadBranch(dataDir, specId, branchName);
    if (existing !== null) {
        throw new Error(`Branch "${branchName}" already exists for spec ${specId}. Choose a different name.`);
    }
    const fromVersion = input.fromVersion ?? (await getLatestVersionTag(dataDir, specId)) ?? 'unversioned';
    const branch = {
        name: branchName,
        specId,
        createdAt: new Date().toISOString(),
        fromVersion,
        content,
    };
    await saveBranch(dataDir, branch);
    return branch;
}
/** Update the content of an existing branch. Throws if not found. */
export async function updateBranchContent(dataDir, specId, branchName, newContent) {
    const existing = await loadBranch(dataDir, specId, branchName);
    if (existing === null) {
        throw new Error(`Branch "${branchName}" not found for spec ${specId}.`);
    }
    const updated = { ...existing, content: newContent };
    await saveBranch(dataDir, updated);
    return updated;
}
/** List all branches for a spec. Returns empty array if none found. */
export async function listBranches(dataDir, specId) {
    const { readdir } = await import('node:fs/promises');
    const dir = getBranchesDir(dataDir, specId);
    if (!existsSync(dir)) {
        return [];
    }
    try {
        const files = await readdir(dir);
        const branches = [];
        for (const file of files) {
            if (!file.endsWith('.json')) {
                continue;
            }
            const filePath = join(dir, file);
            try {
                const raw = await readFile(filePath, 'utf-8');
                branches.push(JSON.parse(raw));
            }
            catch {
                // Skip corrupt files
            }
        }
        return branches.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
    }
    catch {
        return [];
    }
}
/** Delete a branch after a successful merge. Returns true if deleted, false if not found. */
export async function deleteBranch(dataDir, specId, branchName) {
    const filePath = getBranchFilePath(dataDir, specId, branchName);
    try {
        await unlink(filePath);
        return true;
    }
    catch {
        return false;
    }
}
//# sourceMappingURL=brancher.js.map