import { git, resolveProjectPath, resolveBaseBranch, mergeConfig } from './git-helpers.js';
import { specStore } from '../../storage/index.js';
export async function handleRelease(projectId, config) {
    const projectPath = await resolveProjectPath(projectId);
    const mergedConfig = mergeConfig(config);
    // Get the latest tag to determine current version
    const currentVersion = await resolveCurrentVersion(projectPath);
    // Analyze commits since last tag to determine bump type
    const commitsSinceTag = await resolveCommitsSinceTag(projectPath, currentVersion);
    const bumpType = determineBumpType(commitsSinceTag);
    const nextVersion = bumpVersion(currentVersion, bumpType);
    const tagName = `v${nextVersion}`;
    const baseBranch = await resolveBaseBranch(projectPath, mergedConfig.baseBranch);
    // Get completed specs for release notes
    const allSpecs = await specStore.listSpecs(projectId);
    const completedSpecs = allSpecs.filter((s) => s.status === 'done');
    const releaseNotes = buildReleaseNotes(nextVersion, commitsSinceTag, completedSpecs);
    // Determine if we need a release branch (gitflow)
    const needsReleaseBranch = baseBranch === 'develop';
    const releaseBranch = needsReleaseBranch ? `release/${tagName}` : undefined;
    const mergeInstructions = [];
    if (releaseBranch) {
        mergeInstructions.push(`git checkout -b ${releaseBranch}`, `# Test and finalize on ${releaseBranch}`, `git checkout main && git merge --no-ff ${releaseBranch}`, `git tag -a ${tagName} -m "Release ${tagName}"`, `git checkout develop && git merge --no-ff ${releaseBranch}`, `git branch -d ${releaseBranch}`);
    }
    else {
        mergeInstructions.push(`git tag -a ${tagName} -m "Release ${tagName}"`, `git push origin main --follow-tags`);
    }
    const result = {
        action: 'release',
        version: nextVersion,
        bumpType,
        tagName,
        releaseBranch,
        releaseNotes,
        mergeInstructions,
        message: `Release ${tagName} prepared (${bumpType} bump from ${currentVersion})`,
    };
    return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
}
async function resolveCurrentVersion(projectPath) {
    try {
        const { stdout } = await git(projectPath, [
            'describe',
            '--tags',
            '--abbrev=0',
            '--match',
            'v*',
        ]);
        return stdout.trim().replace(/^v/, '');
    }
    catch {
        return '0.0.0';
    }
}
async function resolveCommitsSinceTag(projectPath, currentVersion) {
    try {
        const { stdout } = await git(projectPath, [
            'log',
            `v${currentVersion}..HEAD`,
            '--format=%s',
            '--no-decorate',
        ]);
        return stdout.trim().split('\n').filter(Boolean);
    }
    catch {
        // No previous tag — get last 50 commits
        const { stdout } = await git(projectPath, ['log', '--format=%s', '--no-decorate', '-50']);
        return stdout.trim().split('\n').filter(Boolean);
    }
}
export async function handleHotfix(projectId, _config) {
    const projectPath = await resolveProjectPath(projectId);
    // Get the latest production tag
    let latestTag = 'v0.0.0';
    try {
        const { stdout } = await git(projectPath, [
            'describe',
            '--tags',
            '--abbrev=0',
            '--match',
            'v*',
        ]);
        latestTag = stdout.trim();
    }
    catch {
        // No tags yet
    }
    const currentVersion = latestTag.replace(/^v/, '');
    const hotfixVersion = bumpVersion(currentVersion, 'patch');
    const hotfixBranch = `hotfix/v${hotfixVersion}`;
    // Create hotfix branch from latest tag
    try {
        await git(projectPath, ['checkout', '-b', hotfixBranch, latestTag]);
    }
    catch (err) {
        // If branch already exists, just report
        /* v8 ignore start */
        const message = err instanceof Error ? err.message : String(err);
        /* v8 ignore end */
        if (!message.includes('already exists')) {
            throw err;
        }
    }
    const mergeInstructions = [
        `# After applying the hotfix:`,
        `git checkout main && git merge --no-ff ${hotfixBranch}`,
        `git tag -a v${hotfixVersion} -m "Hotfix v${hotfixVersion}"`,
        `git checkout develop && git merge --no-ff ${hotfixBranch}`,
        `git branch -d ${hotfixBranch}`,
        `git push origin main develop --follow-tags`,
    ];
    const result = {
        action: 'hotfix',
        hotfixBranch,
        baseTag: latestTag,
        hotfixVersion,
        mergeInstructions,
        message: `Hotfix branch '${hotfixBranch}' created from ${latestTag}. Apply fix, then follow merge instructions.`,
    };
    return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
}
export async function handlePromote(projectId, _config) {
    const allSpecs = await specStore.listSpecs(projectId);
    const doneSpecs = allSpecs.filter((s) => s.status === 'done');
    const checklist = {
        devToStaging: [
            { gate: 'Unit tests pass', status: 'manual', responsible: 'developer' },
            { gate: 'Coverage did not drop', status: 'manual', responsible: 'developer' },
            { gate: 'No critical CVEs', status: 'manual', responsible: 'security-lead' },
            { gate: 'Smoke tests OK', status: 'manual', responsible: 'qa' },
            { gate: 'PR approved by at least 1 reviewer', status: 'manual', responsible: 'tech-lead' },
        ],
        stagingToProd: [
            { gate: 'Integration tests pass', status: 'manual', responsible: 'qa' },
            { gate: 'Performance tests pass', status: 'manual', responsible: 'qa' },
            { gate: 'No critical CVEs in staging', status: 'manual', responsible: 'security-lead' },
            { gate: 'Rollback plan documented', status: 'manual', responsible: 'tech-lead' },
            { gate: 'Business stakeholder approval', status: 'manual', responsible: 'product-owner' },
            { gate: 'Maintenance window scheduled if needed', status: 'manual', responsible: 'ops' },
        ],
        specsIncluded: doneSpecs.map((s) => ({ id: s.id, title: s.title })),
    };
    const result = {
        action: 'promote',
        checklist,
        message: `Promotion checklist generated for ${doneSpecs.length} completed spec(s). All gates require manual verification.`,
        note: 'Automation of quality gates is the responsibility of the project CI/CD pipeline.',
    };
    return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
}
function determineBumpType(commits) {
    const hasBreaking = commits.some((c) => c.includes('BREAKING CHANGE') ||
        c.includes('!:') ||
        /^(feat|fix|refactor)(\(.+\))?!:/.test(c));
    if (hasBreaking) {
        return 'major';
    }
    const hasFeature = commits.some((c) => /^feat(\(.+\))?:/.test(c));
    if (hasFeature) {
        return 'minor';
    }
    return 'patch';
}
function bumpVersion(version, bumpType) {
    const parts = version.split('.').map((p) => parseInt(p, 10) || 0);
    /* v8 ignore start */
    const major = parts[0] ?? 0;
    const minor = parts[1] ?? 0;
    const patch = parts[2] ?? 0;
    /* v8 ignore end */
    if (bumpType === 'major') {
        return `${major + 1}.0.0`;
    }
    if (bumpType === 'minor') {
        return `${major}.${minor + 1}.0`;
    }
    return `${major}.${minor}.${patch + 1}`;
}
function buildReleaseNotes(version, commits, specs) {
    const lines = [`# Release v${version}`, '', '## Highlights', ''];
    const features = specs.filter((s) => s.type === 'feature');
    const bugfixes = specs.filter((s) => s.type === 'bugfix');
    if (features.length > 0) {
        lines.push('### New Features');
        for (const s of features) {
            lines.push(`- ${s.title}`);
        }
        lines.push('');
    }
    if (bugfixes.length > 0) {
        lines.push('### Bug Fixes');
        for (const s of bugfixes) {
            lines.push(`- Fixed: ${s.title}`);
        }
        lines.push('');
    }
    const breakingCommits = commits.filter((c) => c.includes('BREAKING') || c.includes('!:'));
    if (breakingCommits.length > 0) {
        lines.push('### Breaking Changes');
        for (const c of breakingCommits) {
            lines.push(`- ${c}`);
        }
        lines.push('');
    }
    lines.push('---');
    lines.push('*Generated by Planu SDD*');
    return lines.join('\n');
}
//# sourceMappingURL=release-ops.js.map