/**
 * Status Command Utilities
 *
 * Helper functions for pause/resume/abandon/status commands
 * Used by slash commands and CLI
 * Part of increment 0007: Smart Status Management
 */
import chalk from 'chalk';
import { MetadataManager } from './metadata-manager.js';
import { IncrementStatus, TYPE_LIMITS, computeTransitionPath } from '../types/increment-metadata.js';
import { resolveEffectiveRoot } from '../../utils/find-project-root.js';
/**
 * Helper: Get WIP limits for increment type
 */
function getTypeLimits(type) {
    const limit = TYPE_LIMITS[type];
    return { max: limit === null ? Infinity : limit };
}
/**
 * Pause an active increment
 */
export async function pauseIncrement(options) {
    const { incrementId, reason, force } = options;
    console.log(chalk.blue(`\n⏸️  Pausing increment ${incrementId}...\n`));
    try {
        // Check if increment exists
        const metadata = MetadataManager.read(incrementId);
        // Validate can pause
        if (metadata.status === IncrementStatus.PAUSED) {
            if (!force) {
                console.log(chalk.yellow(`⚠️  Increment ${incrementId} is already paused`));
                console.log(chalk.gray(`   Previous reason: ${metadata.pausedReason}`));
                console.log(chalk.gray(`   Paused at: ${metadata.pausedAt}`));
                console.log(chalk.gray(`\n   Use --force to update the reason`));
                return;
            }
        }
        else if (metadata.status !== IncrementStatus.ACTIVE) {
            console.log(chalk.red(`❌ Cannot pause increment ${incrementId}`));
            console.log(chalk.gray(`   Current status: ${metadata.status}`));
            console.log(chalk.gray(`   Only active increments can be paused`));
            if (metadata.status === IncrementStatus.ABANDONED) {
                console.log(chalk.gray(`\n   💡 Resume it first: /resume ${incrementId}`));
            }
            process.exit(1);
        }
        // Prompt for reason if not provided
        const pauseReason = reason || 'No reason provided';
        // Update status
        MetadataManager.updateStatus(incrementId, IncrementStatus.PAUSED, pauseReason);
        // Success message
        console.log(chalk.green(`✅ Increment ${incrementId} paused`));
        console.log(chalk.gray(`📝 Reason: ${pauseReason}`));
        console.log(chalk.gray(`⏸️  No longer counts toward active limit`));
        console.log(chalk.gray(`\n💡 Resume with: /resume ${incrementId}\n`));
    }
    catch (error) {
        console.log(chalk.red(`\n❌ Failed to pause increment: ${error instanceof Error ? error.message : String(error)}\n`));
        process.exit(1);
    }
}
/**
 * Resume a paused or abandoned increment
 */
export async function resumeIncrement(options) {
    const { incrementId, force } = options;
    console.log(chalk.blue(`\n▶️  Resuming increment ${incrementId}...\n`));
    try {
        // Check if increment exists
        const metadata = MetadataManager.read(incrementId);
        // Validate can resume
        if (metadata.status === IncrementStatus.ACTIVE) {
            console.log(chalk.yellow(`⚠️  Increment ${incrementId} is already active`));
            console.log(chalk.gray(`   Nothing to resume\n`));
            return;
        }
        if (metadata.status === IncrementStatus.COMPLETED) {
            console.log(chalk.red(`❌ Cannot resume increment ${incrementId}`));
            console.log(chalk.gray(`   Status: completed`));
            console.log(chalk.gray(`   Completed increments cannot be resumed\n`));
            process.exit(1);
        }
        if (metadata.status !== IncrementStatus.PAUSED && metadata.status !== IncrementStatus.ABANDONED) {
            console.log(chalk.red(`❌ Cannot resume increment ${incrementId}`));
            console.log(chalk.gray(`   Current status: ${metadata.status}`));
            console.log(chalk.gray(`   Only paused or abandoned increments can be resumed\n`));
            process.exit(1);
        }
        // Check WIP limits (warn but don't block)
        const activeCount = MetadataManager.getActive().length;
        const type = metadata.type;
        const limits = getTypeLimits(type);
        if (activeCount >= limits.max && limits.max !== Infinity && !force) {
            console.log(chalk.yellow(`\n⚠️  WARNING: WIP Limit Reached`));
            console.log(chalk.gray(`   Current active: ${activeCount}`));
            console.log(chalk.gray(`   Limit for ${type}: ${limits.max}`));
            console.log(chalk.gray(`   Resuming will exceed limit`));
            console.log(chalk.gray(`\n   Complete or pause another increment first`));
            console.log(chalk.gray(`   Or use --force to bypass this warning\n`));
            process.exit(1);
        }
        // Update status
        MetadataManager.updateStatus(incrementId, IncrementStatus.ACTIVE);
        // Success message
        console.log(chalk.green(`✅ Increment ${incrementId} resumed`));
        console.log(chalk.gray(`▶️  Now counts as active`));
        if (metadata.status === IncrementStatus.PAUSED) {
            console.log(chalk.gray(`📝 Was paused for: ${metadata.pausedReason}`));
        }
        else if (metadata.status === IncrementStatus.ABANDONED) {
            console.log(chalk.gray(`📝 Was abandoned for: ${metadata.abandonedReason}`));
        }
        console.log(chalk.gray(`\n💡 Continue work with: /do ${incrementId}\n`));
    }
    catch (error) {
        console.log(chalk.red(`\n❌ Failed to resume increment: ${error instanceof Error ? error.message : String(error)}\n`));
        process.exit(1);
    }
}
/**
 * Abandon an increment
 */
export async function abandonIncrement(options) {
    const { incrementId, reason, force } = options;
    console.log(chalk.blue(`\n🗑️  Abandoning increment ${incrementId}...\n`));
    try {
        // Check if increment exists
        const metadata = MetadataManager.read(incrementId);
        // Validate can abandon
        if (metadata.status === IncrementStatus.ABANDONED) {
            if (!force) {
                console.log(chalk.yellow(`⚠️  Increment ${incrementId} is already abandoned`));
                console.log(chalk.gray(`   Previous reason: ${metadata.abandonedReason}`));
                console.log(chalk.gray(`   Abandoned at: ${metadata.abandonedAt}`));
                console.log(chalk.gray(`\n   Use --force to update the reason`));
                return;
            }
        }
        else if (metadata.status === IncrementStatus.COMPLETED) {
            console.log(chalk.red(`❌ Cannot abandon increment ${incrementId}`));
            console.log(chalk.gray(`   Status: completed`));
            console.log(chalk.gray(`   Completed increments cannot be abandoned\n`));
            process.exit(1);
        }
        // Prompt for reason if not provided
        const abandonReason = reason || 'No reason provided';
        // Confirmation (if not forced)
        if (!force) {
            console.log(chalk.yellow(`⚠️  WARNING: This will permanently abandon the increment`));
            console.log(chalk.gray(`   Reason: ${abandonReason}`));
            console.log(chalk.gray(`\n   Continue? Type 'yes' to confirm, or Ctrl+C to cancel\n`));
            // In a real implementation, would prompt for confirmation
            // For now, proceeding (assuming force or confirmation)
        }
        // Update status
        MetadataManager.updateStatus(incrementId, IncrementStatus.ABANDONED, abandonReason);
        // Success message
        console.log(chalk.green(`✅ Increment ${incrementId} abandoned`));
        console.log(chalk.gray(`📝 Reason: ${abandonReason}`));
        console.log(chalk.gray(`🗑️  No longer counts toward active limit`));
        console.log(chalk.gray(`\n💡 Can be resumed later with: /resume ${incrementId}\n`));
    }
    catch (error) {
        console.log(chalk.red(`\n❌ Failed to abandon increment: ${error instanceof Error ? error.message : String(error)}\n`));
        process.exit(1);
    }
}
/**
 * Complete an active increment
 *
 * This transitions the increment to "completed" status, which triggers:
 * 1. StatusChangeSyncTrigger → External tool sync (GitHub/JIRA/ADO)
 * 2. Living docs update
 *
 * Quality gates (unless skipValidation=true):
 * - All tasks must be marked complete
 * - All ACs must be checked
 * - External tool drift check (warns if >24h, blocks if >7d)
 *
 * @since v4.0 - Auto mode stop hook integration
 */
export async function completeIncrement(options) {
    const { incrementId, silent = false, skipValidation = false } = options;
    const log = (msg) => !silent && console.log(msg);
    log(chalk.blue(`\n✅ Completing increment ${incrementId}...\n`));
    try {
        // Check if increment exists
        const metadata = MetadataManager.read(incrementId);
        // Validate can complete
        if (metadata.status === IncrementStatus.COMPLETED) {
            log(chalk.yellow(`⚠️  Increment ${incrementId} is already completed`));
            return true; // Not an error - already complete
        }
        // Compute transition path to COMPLETED (auto-walk intermediate states)
        const path = computeTransitionPath(metadata.status, IncrementStatus.COMPLETED);
        if (path === null || path.length === 0) {
            log(chalk.red(`❌ Cannot complete increment ${incrementId}`));
            log(chalk.gray(`   Current status: ${metadata.status}`));
            log(chalk.gray(`   No valid transition path to completed`));
            // Always log to stderr so auto/silent mode failures are visible
            process.stderr.write(`[completeIncrement] Cannot complete ${incrementId}: no valid transition from "${metadata.status}" to "completed"\n`);
            return false;
        }
        // Walk intermediate transitions (all states before the final COMPLETED)
        const intermediateSteps = path.slice(0, -1);
        for (const intermediateStatus of intermediateSteps) {
            log(chalk.gray(`   Transitioning: ${metadata.status} → ${intermediateStatus}`));
            try {
                MetadataManager.updateStatus(incrementId, intermediateStatus);
                Object.assign(metadata, MetadataManager.read(incrementId));
            }
            catch (error) {
                const errMsg = error instanceof Error ? error.message : String(error);
                log(chalk.red(`❌ Failed during intermediate transition to ${intermediateStatus}`));
                log(chalk.gray(`   ${errMsg}`));
                process.stderr.write(`[completeIncrement] Failed transition ${incrementId} to "${intermediateStatus}": ${errMsg}\n`);
                return false;
            }
        }
        // Run quality gate validation unless skipped
        if (!skipValidation) {
            // Dynamic import to avoid circular dependency
            const { IncrementCompletionValidator } = await import('./completion-validator.js');
            const validation = await IncrementCompletionValidator.validateCompletion(incrementId);
            if (!validation.isValid) {
                log(chalk.red(`❌ Increment ${incrementId} failed quality gates:\n`));
                validation.errors.forEach((err) => log(chalk.red(`   • ${err}`)));
                if (validation.warnings && validation.warnings.length > 0) {
                    log(chalk.yellow(`\n⚠️  Warnings:\n`));
                    validation.warnings.forEach((warn) => log(chalk.yellow(`   • ${warn}`)));
                }
                // Always log to stderr so auto/silent mode failures are visible
                process.stderr.write(`[completeIncrement] ${incrementId} failed quality gates: ${validation.errors.join('; ')}\n`);
                return false;
            }
            // Show warnings but continue
            if (validation.warnings && validation.warnings.length > 0) {
                log(chalk.yellow(`\n⚠️  Warnings (non-blocking):\n`));
                validation.warnings.forEach((warn) => log(chalk.yellow(`   • ${warn}`)));
            }
        }
        else {
            log(chalk.yellow(`⚠️  Validation skipped — quality gate reports (grill, judge-llm) not checked`));
            log(chalk.gray(`   Run: specweave complete ${incrementId} --yes (without --skip-validation) for enforced closure`));
        }
        // Living docs sync is handled by LifecycleHookDispatcher.onIncrementDone()
        // after status is set to COMPLETED. Suppress StatusChangeSyncTrigger so
        // sync runs exactly once (via onIncrementDone, not twice).
        const { StatusChangeSyncTrigger } = await import('./status-change-sync-trigger.js');
        StatusChangeSyncTrigger.suppressForCompletion = true;
        try {
            MetadataManager.updateStatus(incrementId, IncrementStatus.COMPLETED);
        }
        finally {
            StatusChangeSyncTrigger.suppressForCompletion = false;
        }
        // Dispatch post-increment-done hooks (awaited, error-isolated)
        let hookSyncErrors = [];
        let hookSyncSuccess = [];
        try {
            const { LifecycleHookDispatcher } = await import('../hooks/LifecycleHookDispatcher.js');
            // 0696: `specweave complete` is an explicit user-invoked closure —
            // pass directSync:true so the closure hook runs inline instead of
            // being queued. Without this, JIRA/ADO closure would be deferred.
            const hookResult = await LifecycleHookDispatcher.onIncrementDone(resolveEffectiveRoot(), incrementId, { directSync: true });
            hookSyncErrors = hookResult.syncErrors;
            hookSyncSuccess = hookResult.syncSuccess;
        }
        catch (hookError) {
            const msg = hookError instanceof Error ? hookError.message : String(hookError);
            hookSyncErrors.push(`Hook dispatch failed: ${msg}`);
            process.stderr.write(`[completeIncrement] Post-closure hook error: ${msg}\n`);
        }
        // Direct GitHub issue closure from metadata.
        // Reads issue numbers from metadata.json (populated by the lifecycle hook above)
        // and closes any that are still open. Does NOT re-trigger sync — just closes.
        let ghClosed = 0;
        let ghMilestoneClosed = false;
        const ghErrors = [];
        try {
            const { GitHubReconciler } = await import('../../sync/github-reconciler.js');
            const closureResult = await GitHubReconciler.closeCompletedIncrementIssues(resolveEffectiveRoot(), incrementId, log);
            ghClosed = closureResult.closed;
            ghMilestoneClosed = closureResult.milestoneClose;
            ghErrors.push(...closureResult.errors);
        }
        catch (fallbackError) {
            const msg = fallbackError instanceof Error ? fallbackError.message : String(fallbackError);
            ghErrors.push(msg);
        }
        log(chalk.green(`\n✅ Increment ${incrementId} completed!`));
        log(chalk.gray(`📦 Status changed to: completed`));
        // ── Sync status summary ──────────────────────────────────
        // GitHub issue/milestone closure summary
        if (ghClosed > 0 || ghMilestoneClosed) {
            const parts = [];
            if (ghClosed > 0)
                parts.push(`${ghClosed} issue(s) closed`);
            if (ghMilestoneClosed)
                parts.push('milestone closed');
            log(chalk.green(`   GitHub sync: ${parts.join(', ')}`));
        }
        for (const err of ghErrors) {
            log(chalk.yellow(`   GitHub sync: failed (${err}) — run sw:progress-sync to retry`));
        }
        // Hook-level sync results (living docs, GitHub project, closure coordinator)
        for (const s of hookSyncSuccess) {
            log(chalk.green(`   Sync: ${s}`));
        }
        for (const e of hookSyncErrors) {
            log(chalk.yellow(`   Sync: ${e} — run sw:progress-sync to retry`));
        }
        // Session-end nudge (T-013/T-014). Never blocks closure.
        try {
            const { runSessionEndNudge } = await import('../reflect-nudge/index.js');
            await runSessionEndNudge({
                projectRoot: resolveEffectiveRoot(),
                incrementId,
                silent,
            });
        }
        catch {
            // Nudge is best-effort — close path must never fail on nudge errors.
        }
        return true;
    }
    catch (error) {
        const msg = error instanceof Error ? error.message : String(error);
        log(chalk.red(`\n❌ Failed to complete increment: ${msg}\n`));
        // Always write to stderr so auto/silent mode failures are visible
        process.stderr.write(`[completeIncrement] Unexpected failure for ${incrementId}: ${msg}\n`);
        return false;
    }
}
/**
 * Show status of all increments
 */
export async function showStatus(options = {}) {
    const { verbose, type } = options;
    console.log(chalk.blue.bold(`\n📊 Increment Status\n`));
    try {
        // Get all increments
        let allIncrements = MetadataManager.getAll();
        let increments = allIncrements;
        // Filter by type if specified
        if (type) {
            increments = increments.filter(m => m.type === type);
        }
        // Group by status
        // CRITICAL: "active" includes planning, active, and ready_for_review (all count towards WIP limits)
        const active = increments.filter(m => m.status === IncrementStatus.PLANNING ||
            m.status === IncrementStatus.ACTIVE ||
            m.status === IncrementStatus.READY_FOR_REVIEW);
        const paused = increments.filter(m => m.status === IncrementStatus.PAUSED);
        const completed = increments.filter(m => m.status === IncrementStatus.COMPLETED);
        const abandoned = increments.filter(m => m.status === IncrementStatus.ABANDONED);
        // Calculate overall progress
        const totalIncrements = allIncrements.length;
        const completedCount = allIncrements.filter(m => m.status === IncrementStatus.COMPLETED).length;
        const overallProgress = totalIncrements > 0 ? Math.round((completedCount / totalIncrements) * 100) : 0;
        // Show overall progress (prominent)
        console.log(chalk.cyan.bold(`📈 Overall Progress: ${completedCount}/${totalIncrements} increments complete (${overallProgress}%)`));
        console.log('');
        // Show active increments
        if (active.length > 0) {
            console.log(chalk.cyan.bold(`▶️  Active (${active.length}):`));
            active.forEach(m => {
                const extended = MetadataManager.getExtended(m.id);
                console.log(`  ${chalk.green('●')} ${m.id} [${m.type}]`);
                if (verbose) {
                    console.log(chalk.gray(`     Progress: ${extended.progress || 0}%`));
                    console.log(chalk.gray(`     Age: ${extended.ageInDays} days`));
                }
            });
            console.log('');
        }
        // Show paused increments (ALWAYS show reason - critical info)
        if (paused.length > 0) {
            console.log(chalk.yellow.bold(`⏸️  Paused (${paused.length}):`));
            paused.forEach(m => {
                const extended = MetadataManager.getExtended(m.id);
                console.log(`  ${chalk.yellow('⏸')} ${m.id} [${m.type}]`);
                console.log(chalk.gray(`     Reason: ${m.pausedReason || 'No reason provided'}`));
                if (verbose) {
                    console.log(chalk.gray(`     Paused: ${extended.daysPaused} days ago`));
                }
            });
            console.log('');
        }
        // Show WIP limits status (simplified: just show total active vs limit)
        const totalActive = active.length;
        const overLimit = totalActive > 1;
        const limitIcon = overLimit ? chalk.red('⚠️') : chalk.green('✅');
        console.log(chalk.cyan.bold(`📈 WIP Limit:`));
        console.log(`  ${limitIcon} Active increments: ${totalActive}/1 ${overLimit ? '(EXCEEDS LIMIT!)' : ''}`);
        if (overLimit) {
            console.log(chalk.yellow(`     💡 Run 'specweave pause <id>' to pause one before starting new work`));
        }
        console.log('');
        // Show summary
        console.log(chalk.gray(`📊 Summary:`));
        console.log(chalk.gray(`   Active: ${active.length}`));
        console.log(chalk.gray(`   Paused: ${paused.length}`));
        console.log(chalk.gray(`   Completed: ${completed.length}`));
        console.log(chalk.gray(`   Abandoned: ${abandoned.length}`));
        console.log(chalk.gray(`   Total: ${increments.length}\n`));
        // Show next actions
        if (active.length === 0 && paused.length > 0) {
            console.log(chalk.gray(`💡 Resume a paused increment: /resume <id>`));
        }
        else if (active.length === 0) {
            console.log(chalk.gray(`💡 Start new increment: /inc "feature description"`));
        }
    }
    catch (error) {
        console.log(chalk.red(`\n❌ Failed to show status: ${error instanceof Error ? error.message : String(error)}\n`));
        process.exit(1);
    }
}
//# sourceMappingURL=status-commands.js.map