import { glob } from 'glob';
import { readFileSync, existsSync } from 'fs';
import { join, basename } from 'path';
import { scanLiteTasks } from './lite-scanner.js';
import { createDashboardCache } from './cache-manager.js';
/**
 * Aggregate all data for dashboard rendering (with caching)
 * @param sessions - Scanned sessions from session-scanner
 * @param workflowDir - Path to .workflow directory
 * @returns Aggregated dashboard data
 */
export async function aggregateData(sessions, workflowDir) {
    // Initialize cache manager
    const cache = createDashboardCache(workflowDir);
    // Prepare paths to watch for changes (includes both new dual files and legacy)
    const watchPaths = [
        join(workflowDir, 'active'),
        join(workflowDir, 'archives'),
        join(workflowDir, 'project-tech.json'),
        join(workflowDir, 'project-guidelines.json'),
        join(workflowDir, 'project.json'), // Legacy support
        ...sessions.active.map(s => s.path),
        ...sessions.archived.map(s => s.path)
    ];
    // Check cache first
    const cachedData = await cache.get(watchPaths);
    if (cachedData !== null) {
        console.log('Using cached dashboard data');
        return cachedData;
    }
    console.log('Cache miss - regenerating dashboard data');
    const data = {
        generatedAt: new Date().toISOString(),
        activeSessions: [],
        archivedSessions: [],
        liteTasks: {
            litePlan: [],
            liteFix: []
        },
        reviewData: null,
        projectOverview: null,
        statistics: {
            totalSessions: 0,
            activeSessions: 0,
            totalTasks: 0,
            completedTasks: 0,
            reviewFindings: 0,
            litePlanCount: 0,
            liteFixCount: 0
        }
    };
    // Process active sessions
    for (const session of sessions.active) {
        const sessionData = await processSession(session, true);
        data.activeSessions.push(sessionData);
        data.statistics.totalTasks += sessionData.tasks.length;
        data.statistics.completedTasks += sessionData.tasks.filter(t => t.status === 'completed').length;
    }
    // Process archived sessions
    for (const session of sessions.archived) {
        const sessionData = await processSession(session, false);
        data.archivedSessions.push(sessionData);
        data.statistics.totalTasks += sessionData.taskCount || 0;
        data.statistics.completedTasks += sessionData.taskCount || 0;
    }
    // Aggregate review data if present
    if (sessions.hasReviewData) {
        data.reviewData = await aggregateReviewData(sessions.active);
        data.statistics.reviewFindings = data.reviewData.totalFindings;
    }
    data.statistics.totalSessions = sessions.active.length + sessions.archived.length;
    data.statistics.activeSessions = sessions.active.length;
    // Scan and include lite tasks
    try {
        const liteTasks = await scanLiteTasks(workflowDir);
        data.liteTasks = liteTasks;
        data.statistics.litePlanCount = liteTasks.litePlan.length;
        data.statistics.liteFixCount = liteTasks.liteFix.length;
    }
    catch (err) {
        console.error('Error scanning lite tasks:', err.message);
    }
    // Load project overview from project.json
    try {
        data.projectOverview = loadProjectOverview(workflowDir);
    }
    catch (err) {
        console.error('Error loading project overview:', err.message);
    }
    // Store in cache before returning
    await cache.set(data, watchPaths);
    return data;
}
/**
 * Process a single session, loading tasks and review info
 * @param session - Session object from scanner
 * @param isActive - Whether session is active
 * @returns Processed session data
 */
async function processSession(session, isActive) {
    const result = {
        session_id: session.session_id || session.id || '',
        project: session.project || session.description || session.session_id || session.id || '',
        status: session.status || (isActive ? 'active' : 'archived'),
        type: session.type || 'workflow', // Session type (workflow, review, test, docs)
        workflow_type: session.workflow_type || null, // Original workflow_type for reference
        created_at: session.created || session.created_at || null, // Prefer 'created' from SessionMetadata, fallback to 'created_at'
        archived_at: session.archived_at || null, // Raw ISO string - let frontend format
        path: session.path,
        tasks: [],
        taskCount: 0,
        hasReview: false,
        reviewSummary: null,
        reviewDimensions: []
    };
    // Load tasks for active sessions (full details)
    if (isActive) {
        const taskDir = join(session.path, '.task');
        if (existsSync(taskDir)) {
            const taskFiles = await safeGlob('IMPL-*.json', taskDir);
            for (const taskFile of taskFiles) {
                try {
                    const taskData = JSON.parse(readFileSync(join(taskDir, taskFile), 'utf8'));
                    result.tasks.push({
                        task_id: taskData.id || basename(taskFile, '.json'),
                        title: taskData.title || 'Untitled Task',
                        status: taskData.status || 'pending',
                        type: taskData.meta?.type || 'task',
                        meta: taskData.meta || {},
                        context: taskData.context || {},
                        flow_control: taskData.flow_control || {}
                    });
                }
                catch {
                    // Skip invalid task files
                }
            }
            // Sort tasks by ID
            result.tasks.sort((a, b) => sortTaskIds(a.task_id, b.task_id));
        }
        result.taskCount = result.tasks.length;
        // Check for review data
        const reviewDir = join(session.path, '.review');
        if (existsSync(reviewDir)) {
            result.hasReview = true;
            result.reviewSummary = loadReviewSummary(reviewDir);
            // Load dimension data for review sessions
            if (session.type === 'review') {
                result.reviewDimensions = await loadDimensionData(reviewDir);
            }
        }
    }
    else {
        // For archived, also load tasks (same as active)
        const taskDir = join(session.path, '.task');
        if (existsSync(taskDir)) {
            const taskFiles = await safeGlob('IMPL-*.json', taskDir);
            for (const taskFile of taskFiles) {
                try {
                    const taskData = JSON.parse(readFileSync(join(taskDir, taskFile), 'utf8'));
                    result.tasks.push({
                        task_id: taskData.id || basename(taskFile, '.json'),
                        title: taskData.title || 'Untitled Task',
                        status: taskData.status || 'completed', // Archived tasks are usually completed
                        type: taskData.meta?.type || 'task'
                    });
                }
                catch {
                    // Skip invalid task files
                }
            }
            // Sort tasks by ID
            result.tasks.sort((a, b) => sortTaskIds(a.task_id, b.task_id));
            result.taskCount = result.tasks.length;
        }
        // Check for review data in archived sessions too
        const reviewDir = join(session.path, '.review');
        if (existsSync(reviewDir)) {
            result.hasReview = true;
            result.reviewSummary = loadReviewSummary(reviewDir);
            // Load dimension data for review sessions
            if (session.type === 'review') {
                result.reviewDimensions = await loadDimensionData(reviewDir);
            }
        }
    }
    return result;
}
/**
 * Aggregate review data from all active sessions with reviews
 * @param activeSessions - Active session objects
 * @returns Aggregated review data
 */
async function aggregateReviewData(activeSessions) {
    const reviewData = {
        totalFindings: 0,
        severityDistribution: { critical: 0, high: 0, medium: 0, low: 0 },
        dimensionSummary: {},
        sessions: []
    };
    for (const session of activeSessions) {
        const reviewDir = join(session.path, '.review');
        if (!existsSync(reviewDir))
            continue;
        const reviewProgress = loadReviewProgress(reviewDir);
        const dimensionData = await loadDimensionData(reviewDir);
        if (reviewProgress || dimensionData.length > 0) {
            const sessionReview = {
                session_id: session.session_id || session.id || '',
                progress: reviewProgress,
                dimensions: dimensionData,
                findings: []
            };
            // Collect and count findings
            for (const dim of dimensionData) {
                if (dim.findings && Array.isArray(dim.findings)) {
                    for (const finding of dim.findings) {
                        const severity = (finding.severity || 'low').toLowerCase();
                        if (reviewData.severityDistribution.hasOwnProperty(severity)) {
                            reviewData.severityDistribution[severity]++;
                        }
                        reviewData.totalFindings++;
                        sessionReview.findings.push({
                            ...finding,
                            dimension: dim.name
                        });
                    }
                }
                // Track dimension summary
                if (!reviewData.dimensionSummary[dim.name]) {
                    reviewData.dimensionSummary[dim.name] = { count: 0, sessions: [] };
                }
                reviewData.dimensionSummary[dim.name].count += dim.findings?.length || 0;
                reviewData.dimensionSummary[dim.name].sessions.push(session.session_id || session.id || '');
            }
            reviewData.sessions.push(sessionReview);
        }
    }
    return reviewData;
}
/**
 * Load review progress from review-progress.json
 * @param reviewDir - Path to .review directory
 * @returns Review progress data or null
 */
function loadReviewProgress(reviewDir) {
    const progressFile = join(reviewDir, 'review-progress.json');
    if (!existsSync(progressFile))
        return null;
    try {
        return JSON.parse(readFileSync(progressFile, 'utf8'));
    }
    catch {
        return null;
    }
}
/**
 * Load review summary from review-state.json
 * @param reviewDir - Path to .review directory
 * @returns Review summary or null
 */
function loadReviewSummary(reviewDir) {
    const stateFile = join(reviewDir, 'review-state.json');
    if (!existsSync(stateFile))
        return null;
    try {
        const state = JSON.parse(readFileSync(stateFile, 'utf8'));
        return {
            phase: state.phase || 'unknown',
            severityDistribution: state.severity_distribution || {},
            criticalFiles: (state.critical_files || []).slice(0, 3),
            status: state.status || 'in_progress'
        };
    }
    catch {
        return null;
    }
}
/**
 * Load dimension data from .review/dimensions/
 * @param reviewDir - Path to .review directory
 * @returns Array of dimension data
 */
async function loadDimensionData(reviewDir) {
    const dimensionsDir = join(reviewDir, 'dimensions');
    if (!existsSync(dimensionsDir))
        return [];
    const dimensions = [];
    const dimFiles = await safeGlob('*.json', dimensionsDir);
    for (const file of dimFiles) {
        try {
            const data = JSON.parse(readFileSync(join(dimensionsDir, file), 'utf8'));
            // Handle array structure: [ { findings: [...], summary: {...} } ]
            let findings = [];
            let summary = null;
            let status = 'completed';
            if (Array.isArray(data) && data.length > 0) {
                const dimData = data[0];
                findings = dimData.findings || [];
                summary = dimData.summary || null;
                status = dimData.status || 'completed';
            }
            else if (data.findings) {
                const dataObj = data;
                findings = dataObj.findings || [];
                summary = dataObj.summary || null;
                status = dataObj.status || 'completed';
            }
            dimensions.push({
                name: basename(file, '.json'),
                findings: findings,
                summary: summary,
                status: status
            });
        }
        catch {
            // Skip invalid dimension files
        }
    }
    return dimensions;
}
/**
 * Safe glob wrapper that returns empty array on error
 * @param pattern - Glob pattern
 * @param cwd - Current working directory
 * @returns Array of matching file names
 */
async function safeGlob(pattern, cwd) {
    try {
        return await glob(pattern, { cwd, absolute: false });
    }
    catch {
        return [];
    }
}
// formatDate removed - dates are now passed as raw ISO strings
// Frontend (dashboard.js) handles all date formatting
/**
 * Sort task IDs numerically (IMPL-1, IMPL-2, IMPL-1.1, etc.)
 * @param a - First task ID
 * @param b - Second task ID
 * @returns Comparison result
 */
function sortTaskIds(a, b) {
    const parseId = (id) => {
        const match = id.match(/IMPL-(\d+)(?:\.(\d+))?/);
        if (!match)
            return [0, 0];
        return [parseInt(match[1]), parseInt(match[2] || '0')];
    };
    const [a1, a2] = parseId(a);
    const [b1, b2] = parseId(b);
    return a1 - b1 || a2 - b2;
}
/**
 * Load project overview from project-tech.json and project-guidelines.json
 * Supports dual file structure with backward compatibility for legacy project.json
 * @param workflowDir - Path to .workflow directory
 * @returns Project overview data or null if not found
 */
function loadProjectOverview(workflowDir) {
    const techFile = join(workflowDir, 'project-tech.json');
    const guidelinesFile = join(workflowDir, 'project-guidelines.json');
    const legacyFile = join(workflowDir, 'project.json');
    // Check for new dual file structure first, fallback to legacy
    const useLegacy = !existsSync(techFile) && existsSync(legacyFile);
    const projectFile = useLegacy ? legacyFile : techFile;
    if (!existsSync(projectFile)) {
        console.log(`Project file not found at: ${projectFile}`);
        return null;
    }
    try {
        const fileContent = readFileSync(projectFile, 'utf8');
        const projectData = JSON.parse(fileContent);
        console.log(`Successfully loaded project overview: ${projectData.project_name || 'Unknown'} (${useLegacy ? 'legacy' : 'tech'})`);
        // Parse tech data (compatible with both legacy and new structure)
        const overview = projectData.overview;
        const technologyAnalysis = projectData.technology_analysis;
        const developmentStatus = projectData.development_status;
        // Support both old and new schema field names
        const technologyStack = (overview?.technology_stack || technologyAnalysis?.technology_stack);
        const architecture = (overview?.architecture || technologyAnalysis?.architecture);
        const developmentIndex = (projectData.development_index || developmentStatus?.development_index);
        const statistics = (projectData.statistics || developmentStatus?.statistics);
        const metadata = projectData._metadata;
        // Load guidelines from separate file if exists
        let guidelines = null;
        if (existsSync(guidelinesFile)) {
            try {
                const guidelinesContent = readFileSync(guidelinesFile, 'utf8');
                const guidelinesData = JSON.parse(guidelinesContent);
                const conventions = guidelinesData.conventions;
                const constraints = guidelinesData.constraints;
                guidelines = {
                    conventions: {
                        coding_style: conventions?.coding_style || [],
                        naming_patterns: conventions?.naming_patterns || [],
                        file_structure: conventions?.file_structure || [],
                        documentation: conventions?.documentation || []
                    },
                    constraints: {
                        architecture: constraints?.architecture || [],
                        tech_stack: constraints?.tech_stack || [],
                        performance: constraints?.performance || [],
                        security: constraints?.security || []
                    },
                    quality_rules: guidelinesData.quality_rules || [],
                    learnings: guidelinesData.learnings || [],
                    _metadata: guidelinesData._metadata
                };
                console.log(`Successfully loaded project guidelines`);
            }
            catch (guidelinesErr) {
                console.error(`Failed to parse project-guidelines.json:`, guidelinesErr.message);
            }
        }
        return {
            projectName: projectData.project_name || 'Unknown',
            description: overview?.description || '',
            initializedAt: projectData.initialized_at || null,
            technologyStack: {
                languages: technologyStack?.languages || [],
                frameworks: technologyStack?.frameworks || [],
                build_tools: technologyStack?.build_tools || [],
                test_frameworks: technologyStack?.test_frameworks || []
            },
            architecture: {
                style: architecture?.style || 'Unknown',
                layers: architecture?.layers || [],
                patterns: architecture?.patterns || []
            },
            keyComponents: overview?.key_components || [],
            features: projectData.features || [],
            developmentIndex: {
                feature: developmentIndex?.feature || [],
                enhancement: developmentIndex?.enhancement || [],
                bugfix: developmentIndex?.bugfix || [],
                refactor: developmentIndex?.refactor || [],
                docs: developmentIndex?.docs || []
            },
            statistics: {
                total_features: statistics?.total_features || 0,
                total_sessions: statistics?.total_sessions || 0,
                last_updated: statistics?.last_updated || null
            },
            metadata: {
                initialized_by: metadata?.initialized_by || 'unknown',
                analysis_timestamp: metadata?.analysis_timestamp || null,
                analysis_mode: metadata?.analysis_mode || 'unknown'
            },
            guidelines
        };
    }
    catch (err) {
        console.error(`Failed to parse project file at ${projectFile}:`, err.message);
        console.error('Error stack:', err.stack);
        return null;
    }
}
//# sourceMappingURL=data-aggregator.js.map