import { specStore, knowledgeStore } from '../storage/index.js';
import { checkConstitutionCompliance } from './create-spec-tech.js';
import { withAudit } from '../engine/autopilot/audit-logger.js';
import { hasPending, markPending, clearPending } from '../engine/autopilot/cascade-deduplicator.js';
export async function runImplementingActions(projectId, specId) {
    let autoBranch;
    let protectedBranchWarning = null;
    // Check if on a protected branch
    try {
        const { resolveProjectPath, git: gitCmd } = await import('./git/git-helpers.js');
        const projectPath = await resolveProjectPath(projectId);
        const { stdout } = await gitCmd(projectPath, ['rev-parse', '--abbrev-ref', 'HEAD']);
        const currentBranch = stdout.trim();
        const protectedBranches = ['main', 'master', 'develop', 'production'];
        if (protectedBranches.includes(currentBranch)) {
            protectedBranchWarning = `Currently on protected branch '${currentBranch}'. Consider switching to a feature branch.`;
        }
    }
    catch {
        // Not a git repo — skip check
    }
    // Auto-create branch
    const foundSpec = await specStore.getSpec(projectId, specId);
    if (foundSpec && !foundSpec.gitBranch) {
        let branchResult;
        try {
            const { resolveProjectPath: resolveBranchPath } = await import('./git/git-helpers.js');
            const { handleCreateBranch } = await import('./git/branch-ops.js');
            const branchProjectPath = await resolveBranchPath(projectId);
            branchResult = await withAudit(branchProjectPath, 'update_status(implementing)', 'handleCreateBranch', () => handleCreateBranch(projectId, specId), (r) => ({ isError: r.isError }));
        }
        catch {
            const { handleCreateBranch } = await import('./git/branch-ops.js');
            branchResult = await handleCreateBranch(projectId, specId);
        }
        if (!branchResult.isError) {
            try {
                const branchData = JSON.parse(branchResult.content[0]?.text ?? '{}');
                autoBranch = branchData.branchName;
            }
            catch {
                // ignore parse error
            }
        }
    }
    // -------------------------------------------------------------------------
    // SPEC-600: Fire-and-forget cascade — recommend_model, orchestration plan, context check
    // -------------------------------------------------------------------------
    const autopilotSummary = [];
    void (async () => {
        try {
            const { resolveProjectPath: resolveCascadePath } = await import('./git/git-helpers.js');
            const projectPath = await resolveCascadePath(projectId);
            const spec = foundSpec ?? (await specStore.getSpec(projectId, specId));
            void Promise.allSettled([
                // SPEC-633: Write session state when spec moves to implementing
                (async () => {
                    const { writeSpecSessionState } = await import('../engine/session-state/writer.js');
                    await writeSpecSessionState(projectPath, specId, spec?.title ?? specId, 'moved to implementing').catch(() => {
                        /* best-effort */
                    });
                })(),
                // SPEC-635: Regenerate context.md
                (async () => {
                    const { generateContextMd } = await import('../engine/context-md-generator.js');
                    await generateContextMd(projectPath, projectId).catch(() => {
                        /* best-effort */
                    });
                })(),
                // SPEC-656: Recalculate epicProgress when spec moves to implementing
                (async () => {
                    try {
                        const { updateEpicProgressInSession } = await import('../engine/session-state/writer.js');
                        const allSpecs = await specStore.listSpecs(projectId);
                        await updateEpicProgressInSession(projectPath, allSpecs).catch(() => {
                            /* best-effort */
                        });
                    }
                    catch {
                        /* best-effort */
                    }
                })(),
                // recommend_model — suggest haiku/sonnet/opus based on spec complexity
                (async () => {
                    try {
                        const { handleRecommendModel } = await import('./recommend-model-handler.js');
                        const result = handleRecommendModel({ specId });
                        if (!result.isError) {
                            autopilotSummary.push('recommend_model: auto-recommended');
                        }
                    }
                    catch {
                        /* best-effort */
                    }
                })(),
                // generate_orchestration_plan — if cross-module or high difficulty
                (async () => {
                    try {
                        const scope = spec?.scope ?? '';
                        const difficulty = spec?.difficulty ?? 1;
                        if (scope === 'cross-module' || difficulty >= 3) {
                            const { handleGenerateOrchestrationScript } = await import('./generate-orchestration-script.js');
                            handleGenerateOrchestrationScript({
                                specIds: [specId],
                                projectPath,
                            });
                            autopilotSummary.push('generate_orchestration_plan: auto-generated');
                        }
                    }
                    catch {
                        /* best-effort */
                    }
                })(),
                // context_window_status — check context weight and warn
                (async () => {
                    try {
                        const { handleContextWindowStatus } = await import('./context-manager-handler.js');
                        const ctxResult = await handleContextWindowStatus({ projectPath });
                        if (!ctxResult.isError) {
                            autopilotSummary.push('context_window_status: checked');
                        }
                    }
                    catch {
                        /* best-effort */
                    }
                })(),
            ]);
        }
        catch {
            // Project path unavailable — skip cascade silently
        }
    })();
    return {
        autoBranch,
        protectedBranchWarning,
        suggestions: [
            'Run generate_execution_plan for a step-by-step implementation guide',
            'Run generate_tests to scaffold test files',
        ],
        autopilotSummary,
    };
}
export async function runDoneActions(projectId, specId, gitBranch) {
    // -------------------------------------------------------------------------
    // SPEC-628: Group A — fast synchronous checks only (< 100ms each)
    // Validation removed: already done by runValidateGate in index.ts (BATCH B)
    // -------------------------------------------------------------------------
    const [recordActualResult, uncommittedResult] = await Promise.allSettled([
        // SPEC-287: Suggest recording actual hours when spec has an estimation
        (async () => {
            try {
                const spec = await specStore.getSpec(projectId, specId);
                if (spec?.estimation) {
                    const estHours = spec.estimation.devHours + spec.estimation.reviewHours;
                    if (estHours > 0) {
                        return `Don't forget to record actual hours: record_actual({ specId: "${specId}", actualHours: <N> }) — estimated: ${String(estHours)}h`;
                    }
                }
            }
            catch {
                // best-effort — never blocks transition
            }
            return null;
        })(),
        // Warn if non-planu changes remain. Planu autocommit/staging is opt-in only.
        (async () => {
            try {
                const { resolveProjectPath, git: gitCmd } = await import('./git/git-helpers.js');
                const projectPath = await resolveProjectPath(projectId);
                if (process.env.PLANU_ENABLE_AUTOCOMMIT === 'true') {
                    await gitCmd(projectPath, ['add', 'planu/']);
                    const { planuAutoCommit } = await import('../engine/git/planu-autocommit.js');
                    void planuAutoCommit({ projectPath, specId, reason: 'mark-done' }).catch((err) => {
                        console.error('[update-status] planuAutoCommit failed:', err instanceof Error ? err.message : String(err));
                    });
                }
                const { stdout } = await gitCmd(projectPath, ['status', '--porcelain']);
                const nonPlanuLines = stdout
                    .trim()
                    .split('\n')
                    .filter((line) => line.trim().length > 0 && !line.includes('planu/'));
                if (nonPlanuLines.length > 0) {
                    return `⚠️ Note: You have unsaved changes outside planu/. Consider committing them before closing this spec.`;
                }
            }
            catch {
                // Not a git repo or git unavailable — skip check
            }
            return null;
        })(),
    ]);
    const recordActualHint = recordActualResult.status === 'fulfilled' ? recordActualResult.value : null;
    const uncommittedWarning = uncommittedResult.status === 'fulfilled' ? uncommittedResult.value : null;
    // -------------------------------------------------------------------------
    // SPEC-628: Group B — merge-check only (PR generation moved to Group C)
    // -------------------------------------------------------------------------
    let mergeWarning = null;
    if (gitBranch) {
        const mergeResult = await Promise.resolve((async () => {
            try {
                const { resolveProjectPath, git: gitCmd } = await import('./git/git-helpers.js');
                const projectPath = await resolveProjectPath(projectId);
                const { stdout } = await gitCmd(projectPath, ['branch', '--merged', 'develop']);
                const mergedBranches = stdout.split('\n').map((b) => b.trim().replace('* ', ''));
                if (!mergedBranches.includes(gitBranch)) {
                    return `Branch '${gitBranch}' has not been merged to develop yet. Consider merging before marking as done.`;
                }
            }
            catch {
                // Not a git repo or branch check failed — skip
            }
            return null;
        })());
        mergeWarning = mergeResult;
    }
    // -------------------------------------------------------------------------
    // Group C — fire-and-forget side effects: launch all in parallel, don't await
    // -------------------------------------------------------------------------
    void (async () => {
        try {
            const { resolveProjectPath } = await import('./git/git-helpers.js');
            const projectPath = await resolveProjectPath(projectId);
            // AC-01: Cleanup worktree, local branch, and remote branch for done spec (best-effort)
            // SPEC-491: Sweep planu/ to remove legacy files
            // SPEC-496: Auto-generate portable session context snapshot
            void Promise.allSettled([
                (async () => {
                    const { cleanupSpecOnDone } = await import('./git/cleanup-ops.js');
                    await withAudit(projectPath, 'update_status(done)', 'cleanupSpecOnDone', () => cleanupSpecOnDone(projectPath, specId, gitBranch)).catch(() => {
                        /* best-effort — never blocks status transition */
                    });
                })(),
                // SPEC-633: Remove spec from session.json index when done
                (async () => {
                    const { removeSpecFromSession } = await import('../engine/session-state/writer.js');
                    await removeSpecFromSession(projectPath, specId).catch(() => {
                        /* best-effort */
                    });
                })(),
                // SPEC-656: Recalculate epicProgress after status change
                (async () => {
                    try {
                        const { updateEpicProgressInSession } = await import('../engine/session-state/writer.js');
                        const allSpecs = await specStore.listSpecs(projectId);
                        await updateEpicProgressInSession(projectPath, allSpecs).catch(() => {
                            /* best-effort */
                        });
                    }
                    catch {
                        /* best-effort */
                    }
                })(),
                // SPEC-635: Regenerate context.md after status change
                (async () => {
                    const { generateContextMd } = await import('../engine/context-md-generator.js');
                    await generateContextMd(projectPath, projectId).catch(() => {
                        /* best-effort */
                    });
                })(),
                (async () => {
                    const { join } = await import('node:path');
                    const { cleanPlanuRoot } = await import('../engine/spec-migrator/planu-root-cleaner.js');
                    await cleanPlanuRoot(join(projectPath, 'planu')).catch(() => {
                        /* best-effort */
                    });
                })(),
                // SPEC-1002: Auto-cleanup stale branches/worktrees when spec reaches done
                (async () => {
                    try {
                        const { runHousekeepingSweep } = await import('../engine/housekeeping/index.js');
                        await runHousekeepingSweep({ projectPath, dryRun: false }).catch(() => {
                            /* best-effort — never blocks status transition */
                        });
                    }
                    catch {
                        /* best-effort */
                    }
                })(),
                // SPEC-660: Dedup — session.json update runs once per spec within 5s window
                (async () => {
                    if (hasPending(specId, 'generateSessionContext')) {
                        return;
                    }
                    markPending(specId, 'generateSessionContext');
                    try {
                        const { generateSessionContext } = await import('../engine/session-context-generator.js');
                        await generateSessionContext(projectPath, projectId).catch(() => {
                            /* best-effort — never blocks status transition */
                        });
                    }
                    finally {
                        clearPending(specId, 'generateSessionContext');
                    }
                })(),
                // SPEC-629: Delete ephemeral prompt.md — file served its purpose once implementing starts
                (async () => {
                    /* v8 ignore start */
                    try {
                        const { glob } = await import('glob');
                        const { unlink } = await import('node:fs/promises');
                        const specFiles = await glob(`planu/specs/${specId}-*/prompt.md`, { cwd: projectPath, absolute: true });
                        const exactFile = await glob(`planu/specs/${specId}/prompt.md`, { cwd: projectPath, absolute: true });
                        await Promise.allSettled([...specFiles, ...exactFile].map((f) => unlink(f).catch(() => {
                            /* best-effort */
                        })));
                    }
                    catch {
                        /* best-effort — never blocks status transition */
                    }
                    /* v8 ignore stop */
                })(),
            ]);
        }
        catch {
            // Project path unavailable — skip all fire-and-forget cleanup silently
        }
    })();
    // SPEC-649: slim cascade — 2 actions only
    const autopilotSummary = [
        'session.json: updated (next spec suggested)',
        'releases/pending.json: spec appended',
    ];
    return {
        mergeWarning,
        prSuggestion: null,
        validationWarning: null,
        uncommittedWarning,
        recordActualHint,
        autopilotSummary,
    };
}
/**
 * Best-effort constitution compliance check for status transitions.
 * Returns warnings (never blocks the transition).
 */
export async function checkConstitutionOnTransition(projectId, title, tags) {
    try {
        const constitution = await knowledgeStore.getConstitution(projectId);
        if (!constitution || constitution.principles.length === 0) {
            return [];
        }
        return checkConstitutionCompliance(title, tags, constitution.principles);
    }
    catch {
        // Best-effort: if constitution can't be loaded, skip silently
        return [];
    }
}
//# sourceMappingURL=update-status-actions.js.map