/**
 * Brownfield Analysis Job Launcher
 *
 * Launches brownfield documentation analysis as a background job.
 * Supports long-running analysis of large codebases (1000+ files).
 */
import * as fs from 'node:fs';
import * as path from 'node:path';
import { v4 as uuidv4 } from 'uuid';
import { consoleLogger } from '../../utils/logger.js';
/**
 * Brownfield job state directory
 */
function getJobsDir(projectPath) {
    return path.join(projectPath, '.specweave', 'state', 'jobs', 'brownfield');
}
/**
 * Get job state file path
 */
function getJobStatePath(projectPath, jobId) {
    return path.join(getJobsDir(projectPath), `${jobId}.json`);
}
/**
 * Create initial job state
 */
function createInitialJobState(jobId, config) {
    return {
        id: jobId,
        type: 'brownfield-analysis',
        status: 'pending',
        progress: {
            current: 0,
            total: 5, // 5 phases
            percentage: 0,
            currentItem: 'Initializing',
            itemsCompleted: [],
            itemsFailed: [],
        },
        startedAt: new Date(),
        updatedAt: new Date(),
        config,
    };
}
/**
 * Save job state to filesystem
 */
function saveJobState(projectPath, job) {
    const jobsDir = getJobsDir(projectPath);
    if (!fs.existsSync(jobsDir)) {
        fs.mkdirSync(jobsDir, { recursive: true });
    }
    const statePath = getJobStatePath(projectPath, job.id);
    fs.writeFileSync(statePath, JSON.stringify(job, null, 2));
}
/**
 * Load job state from filesystem
 */
export function loadJobState(projectPath, jobId) {
    const statePath = getJobStatePath(projectPath, jobId);
    if (!fs.existsSync(statePath)) {
        return null;
    }
    try {
        const content = fs.readFileSync(statePath, 'utf-8');
        return JSON.parse(content);
    }
    catch {
        return null;
    }
}
/**
 * List all brownfield jobs for a project
 */
export function listBrownfieldJobs(projectPath) {
    const jobsDir = getJobsDir(projectPath);
    if (!fs.existsSync(jobsDir)) {
        return [];
    }
    const jobs = fs.readdirSync(jobsDir)
        .filter(f => f.endsWith('.json'))
        .map(file => loadJobState(projectPath, file.replace('.json', '')))
        .filter((job) => job !== null);
    // Sort by start date, newest first
    return jobs.sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime());
}
/**
 * Get the most recent active brownfield job
 */
export function getActiveBrownfieldJob(projectPath) {
    const jobs = listBrownfieldJobs(projectPath);
    return jobs.find(j => j.status === 'running' || j.status === 'pending') || null;
}
const PHASE_INDEX = {
    'discovery': 0,
    'code-analysis': 1,
    'doc-matching': 2,
    'discrepancy-detect': 3,
    'reporting': 4,
};
/**
 * Update job progress
 */
export function updateJobProgress(projectPath, jobId, phase, current, total, currentItem) {
    const job = loadJobState(projectPath, jobId);
    if (!job)
        return;
    const phaseNum = PHASE_INDEX[phase];
    job.progress = {
        current: phaseNum,
        total: 5,
        percentage: Math.round((phaseNum / 5) * 100),
        currentItem: currentItem || `Phase: ${phase} (${current}/${total})`,
        itemsCompleted: job.progress.itemsCompleted,
        itemsFailed: job.progress.itemsFailed,
    };
    job.updatedAt = new Date();
    job.status = 'running';
    // Update checkpoint for resume
    const config = job.config;
    config.checkpoint = {
        phase,
        lastProcessedPath: currentItem || '',
        processedCount: current,
    };
    saveJobState(projectPath, job);
}
/**
 * Mark job as completed with full statistics
 */
export function completeJob(projectPath, jobId, discrepancyCount, stats) {
    const job = loadJobState(projectPath, jobId);
    if (!job)
        return;
    const startTime = new Date(job.startedAt).getTime();
    const endTime = Date.now();
    const durationMs = endTime - startTime;
    job.status = 'completed';
    job.completedAt = new Date();
    job.progress = {
        ...job.progress,
        current: 5,
        total: 5,
        percentage: 100,
        currentItem: `Completed: ${discrepancyCount} discrepancies found`,
    };
    job.updatedAt = new Date();
    job.result = {
        discrepancyCount,
        filesAnalyzed: stats?.filesAnalyzed ?? 0,
        modulesDetected: stats?.modulesDetected ?? 0,
        byType: stats?.byType ?? {},
        byPriority: stats?.byPriority ?? {},
        durationMs: stats?.durationMs ?? durationMs,
    };
    saveJobState(projectPath, job);
}
const PRIORITY_ICONS = {
    critical: '🔴',
    high: '🟠',
    medium: '🟡',
    low: '🟢',
};
function formatDuration(ms) {
    const seconds = Math.floor(ms / 1000);
    const minutes = Math.floor(seconds / 60);
    const remainingSeconds = seconds % 60;
    return minutes > 0 ? `${minutes}m ${remainingSeconds}s` : `${seconds}s`;
}
/**
 * Format completion notification for display
 */
export function formatCompletionNotification(jobId, stats) {
    const typeLines = Object.entries(stats.byType)
        .map(([type, count]) => {
        const percentage = Math.round((count / stats.discrepancyCount) * 100);
        return `     ${type.padEnd(15)}: ${String(count).padStart(3)} (${percentage}%)`;
    })
        .join('\n');
    const priorityLines = Object.entries(stats.byPriority)
        .map(([priority, count]) => {
        const icon = PRIORITY_ICONS[priority] ?? '⚪';
        return `     ${icon} ${priority.charAt(0).toUpperCase() + priority.slice(1).padEnd(8)}: ${String(count).padStart(3)}`;
    })
        .join('\n');
    return `
✅ Brownfield Analysis Complete (${jobId})

📊 Results Summary:
   Files analyzed: ${stats.filesAnalyzed.toLocaleString()}
   Modules detected: ${stats.modulesDetected}
   Duration: ${formatDuration(stats.durationMs)}

📋 Discrepancies Found: ${stats.discrepancyCount}
   By Type:
${typeLines}

   By Priority:
${priorityLines}

💡 Next Steps:
   sw:discrepancies           → View all pending discrepancies
   sw:discrepancies --module <name> → Filter by module
   sw:discrepancy-to-increment DISC-0001 DISC-0002 → Create increment
`.trim();
}
/**
 * Mark job as failed
 */
export function failJob(projectPath, jobId, error) {
    const job = loadJobState(projectPath, jobId);
    if (!job)
        return;
    job.status = 'failed';
    job.error = error;
    job.updatedAt = new Date();
    saveJobState(projectPath, job);
}
/**
 * Pause a running job
 */
export function pauseJob(projectPath, jobId) {
    const job = loadJobState(projectPath, jobId);
    if (!job || job.status !== 'running')
        return false;
    job.status = 'paused';
    job.updatedAt = new Date();
    saveJobState(projectPath, job);
    return true;
}
/**
 * Launch brownfield analysis as a background job
 *
 * Note: In the current implementation, this creates the job state
 * but the actual analysis is performed by the brownfield-worker
 * which is invoked separately. For now, this sets up the job
 * for future integration with a proper background process system.
 */
export async function launchBrownfieldAnalysisJob(options) {
    const logger = options.logger ?? consoleLogger;
    const jobId = `bf-${uuidv4().slice(0, 8)}`;
    const config = {
        type: 'brownfield-analysis',
        projectPath: options.projectPath,
        sourceDocsPath: options.sourceDocsPath,
        analysisDepth: options.analysisDepth,
    };
    // Create initial job state
    const job = createInitialJobState(jobId, config);
    saveJobState(options.projectPath, job);
    logger.log(`Created brownfield analysis job: ${jobId}`);
    logger.log(`Analysis depth: ${options.analysisDepth}`);
    if (options.sourceDocsPath) {
        logger.log(`Source docs: ${options.sourceDocsPath}`);
    }
    // Note: In a full implementation, we would spawn a worker process here
    // For now, the job is created and can be executed by the worker manually
    // or as part of the init flow
    return {
        success: true,
        jobId,
        message: `Brownfield analysis job ${jobId} created. Run sw:jobs to monitor.`,
    };
}
/**
 * Resume a paused job
 */
export function resumeJob(projectPath, jobId) {
    const job = loadJobState(projectPath, jobId);
    if (!job || job.status !== 'paused')
        return false;
    job.status = 'running';
    job.updatedAt = new Date();
    saveJobState(projectPath, job);
    return true;
}
/**
 * Delete a job and its state
 */
export function deleteJob(projectPath, jobId) {
    const statePath = getJobStatePath(projectPath, jobId);
    if (!fs.existsSync(statePath))
        return false;
    try {
        fs.unlinkSync(statePath);
        return true;
    }
    catch {
        return false;
    }
}
//# sourceMappingURL=brownfield-launcher.js.map