// engine/spec-versioning/merger.ts — Merge a spec branch back into main with conflict detection
import { loadBranch, deleteBranch } from './brancher.js';
import { createVersion, getLatestVersionTag, loadVersionStore, suggestNextTag, } from './version-store.js';
import { diffContents } from './differ.js';
/**
 * Detect merge conflicts between branch content and latest main content.
 * Simple strategy: if the branch diverged from the latest version, flag it.
 */
export function detectConflicts(baseContent, branchContent, mainContent) {
    const conflicts = [];
    // If main content changed from the base (concurrent edit), flag it
    if (mainContent !== baseContent) {
        const mainLines = new Set(mainContent.split('\n'));
        const branchLines = branchContent.split('\n');
        const conflictingLines = [];
        for (const line of branchLines) {
            if (line.trim().length > 0 && !mainLines.has(line)) {
                conflictingLines.push(line.trim());
            }
        }
        if (conflictingLines.length > 0) {
            conflicts.push({
                type: 'concurrent_edit',
                description: 'The main spec was modified after the branch was created. ' +
                    'Some branch changes conflict with current main content.',
                details: conflictingLines.slice(0, 10), // Show up to 10 conflicting lines
            });
        }
    }
    return conflicts;
}
/**
 * Attempt a simple auto-merge: apply branch additions to main content.
 * Returns merged content or null if auto-merge is not safe.
 */
export function autoMerge(branchContent, mainContent) {
    // Simple strategy: if main has no divergence (same as base), use branch content directly
    if (branchContent === mainContent) {
        return mainContent;
    }
    // For now, trust branch content as the resolved merge when no conflicts are critical
    // A more sophisticated approach would do 3-way merge, but that requires the base content
    return branchContent;
}
/**
 * Merge a spec branch back into main.
 * Creates a new version snapshot with the merged content.
 * Deletes the branch on success.
 */
export async function mergeBranch(dataDir, input) {
    const { specId, branchName, message } = input;
    // Load the branch
    const branch = await loadBranch(dataDir, specId, branchName);
    if (branch === null) {
        return {
            success: false,
            specId,
            branchName,
            conflicts: [],
            message: `Branch "${branchName}" not found for spec ${specId}.`,
        };
    }
    // Load the current main spec content (latest version snapshot)
    const versionStore = await loadVersionStore(dataDir, specId);
    const latestSnapshot = versionStore.versions[versionStore.versions.length - 1];
    const mainContent = latestSnapshot?.content ?? '';
    // Determine the content to use for the merge
    const resolvedContent = input.resolvedContent ?? autoMerge(branch.content, mainContent);
    if (resolvedContent === null) {
        return {
            success: false,
            specId,
            branchName,
            conflicts: [
                {
                    type: 'content_diverged',
                    description: 'Auto-merge failed. Provide resolvedContent to complete the merge.',
                    details: [],
                },
            ],
            message: 'Merge failed: could not auto-merge. Please provide resolvedContent.',
        };
    }
    // Determine the new version tag
    const latestTag = await getLatestVersionTag(dataDir, specId);
    const newVersionTag = input.newVersionTag ?? suggestNextTag(latestTag);
    // Create the new version snapshot
    const newVersion = await createVersion(dataDir, {
        projectId: input.projectId,
        specId,
        tag: newVersionTag,
        content: resolvedContent,
        message: message ?? `Merged branch "${branchName}" into main`,
        author: `merge:${branchName}`,
    });
    // Compute diff for reporting
    const diff = diffContents(specId, branch.fromVersion, newVersionTag, branch.content, resolvedContent);
    // Delete the branch after successful merge
    await deleteBranch(dataDir, specId, branchName);
    const totalChanges = diff.criteriaChanges.added.length +
        diff.criteriaChanges.removed.length +
        diff.criteriaChanges.modified.length;
    return {
        success: true,
        specId,
        branchName,
        newVersionTag: newVersion.tag,
        conflicts: [],
        message: `Merged branch "${branchName}" into spec ${specId} as version ${newVersion.tag}. ` +
            `${totalChanges} AC-level change(s) detected.`,
    };
}
//# sourceMappingURL=merger.js.map