/**
 * Content Distributor for Intelligent Living Docs Sync
 *
 * Distributes classified spec sections to appropriate folders with proper formatting.
 *
 * @module living-docs/content-distributor
 */
import * as fs from '../../utils/fs-native.js';
import path from 'path';
import { ContentCategory } from './content-classifier.js';
/**
 * Content Distributor class
 */
export class ContentDistributor {
    constructor(options = {}) {
        this.options = {
            basePath: options.basePath || path.join(process.cwd(), '.specweave', 'docs', 'internal'),
            generateFrontmatter: options.generateFrontmatter ?? true,
            preserveOriginal: options.preserveOriginal ?? true,
            dryRun: options.dryRun ?? false,
        };
    }
    /**
     * Distribute parsed spec to appropriate locations
     */
    async distribute(incrementId, spec, classifications, project) {
        const result = {
            created: [],
            updated: [],
            skipped: [],
            errors: [],
            summary: {
                totalSections: classifications.length,
                filesCreated: 0,
                filesUpdated: 0,
                filesSkipped: 0,
                errors: 0,
                byCategory: {},
            },
        };
        // Pair sections with classifications
        const classifiedSections = [];
        const flatSections = this.flattenSections(spec.sections);
        for (let i = 0; i < Math.min(flatSections.length, classifications.length); i++) {
            classifiedSections.push({
                section: flatSections[i],
                classification: classifications[i],
            });
            // Count by category
            const category = classifications[i].category;
            result.summary.byCategory[category] = (result.summary.byCategory[category] || 0) + 1;
        }
        // Group sections by category and file
        const fileGroups = this.groupByFile(classifiedSections, project);
        // Write each file group
        for (const [filePath, group] of fileGroups.entries()) {
            try {
                const fileResult = await this.writeFile(incrementId, filePath, group, spec, project);
                if (fileResult.status === 'created') {
                    result.created.push(fileResult.file);
                    result.summary.filesCreated++;
                }
                else if (fileResult.status === 'updated') {
                    result.updated.push(fileResult.file);
                    result.summary.filesUpdated++;
                }
                else if (fileResult.status === 'skipped') {
                    result.skipped.push(fileResult.file);
                    result.summary.filesSkipped++;
                }
            }
            catch (error) {
                result.errors.push({
                    section: group.sections.map((s) => s.section.heading).join(', '),
                    category: group.category,
                    error: String(error),
                    path: filePath,
                });
                result.summary.errors++;
            }
        }
        // Preserve original spec if requested
        if (this.options.preserveOriginal) {
            try {
                await this.archiveOriginalSpec(incrementId, spec, project);
            }
            catch (error) {
                result.errors.push({
                    section: 'Archive Original Spec',
                    category: ContentCategory.Unknown,
                    error: String(error),
                });
                result.summary.errors++;
            }
        }
        return result;
    }
    /**
     * Flatten nested sections
     */
    flattenSections(sections) {
        const result = [];
        for (const section of sections) {
            result.push(section);
            if (section.children.length > 0) {
                result.push(...this.flattenSections(section.children));
            }
        }
        return result;
    }
    /**
     * Group sections by destination file
     */
    groupByFile(classifiedSections, project) {
        const groups = new Map();
        for (const item of classifiedSections) {
            const { classification } = item;
            // Skip unknown categories
            if (classification.category === ContentCategory.Unknown) {
                continue;
            }
            // Resolve path with project
            const filePath = this.resolvePath(classification.suggestedPath, classification.suggestedFilename, project);
            if (!groups.has(filePath)) {
                groups.set(filePath, {
                    category: classification.category,
                    sections: [],
                });
            }
            groups.get(filePath).sections.push(item);
        }
        return groups;
    }
    /**
     * Resolve file path with project
     */
    resolvePath(suggestedPath, filename, project) {
        // Replace {project} placeholder
        const pathWithProject = suggestedPath.replace('{project}', project.id);
        return path.join(this.options.basePath, pathWithProject, filename);
    }
    /**
     * Write a file with grouped sections
     */
    async writeFile(incrementId, filePath, group, spec, project) {
        // Generate content
        const content = this.generateFileContent(incrementId, group, spec, project);
        // Check if file exists
        const exists = fs.existsSync(filePath);
        // In dry run mode, just return what would happen
        if (this.options.dryRun) {
            return {
                status: exists ? 'updated' : 'created',
                file: {
                    path: filePath,
                    category: group.category,
                    size: content.length,
                    sections: group.sections.length,
                },
            };
        }
        // Check if content changed
        if (exists) {
            const existingContent = await fs.readFile(filePath, 'utf-8');
            if (existingContent === content) {
                return {
                    status: 'skipped',
                    file: {
                        path: filePath,
                        category: group.category,
                        size: content.length,
                        sections: group.sections.length,
                    },
                };
            }
        }
        // Ensure directory exists
        await fs.ensureDir(path.dirname(filePath));
        // Write file
        await fs.writeFile(filePath, content, 'utf-8');
        return {
            status: exists ? 'updated' : 'created',
            file: {
                path: filePath,
                category: group.category,
                size: content.length,
                sections: group.sections.length,
            },
        };
    }
    /**
     * Generate file content with frontmatter and sections
     */
    generateFileContent(incrementId, group, spec, project) {
        let content = '';
        // Generate frontmatter
        if (this.options.generateFrontmatter) {
            content += this.generateFrontmatter(incrementId, group, spec, project);
            content += '\n\n';
        }
        // Add sections
        for (const item of group.sections) {
            const { section } = item;
            // Add heading
            content += `${'#'.repeat(section.level)} ${section.heading}\n\n`;
            // Add content
            content += section.content;
            // Add spacing between sections
            content += '\n\n';
        }
        // Add footer
        content += `---\n\n`;
        content += `**Source**: [Increment ${incrementId}](../../../../increments/${incrementId}/spec.md)\n`;
        content += `**Project**: ${project.name}\n`;
        content += `**Last Updated**: ${new Date().toISOString().split('T')[0]}\n`;
        return content.trim() + '\n';
    }
    /**
     * Generate Docusaurus frontmatter
     */
    generateFrontmatter(incrementId, group, spec, project) {
        const firstSection = group.sections[0].section;
        const title = firstSection.heading;
        const category = group.category;
        const frontmatter = {
            id: firstSection.id,
            title,
            sidebar_label: title,
            description: this.generateDescription(group.sections),
            tags: [category, project.id, incrementId],
            increment: incrementId,
            project: project.id,
            category,
            last_updated: new Date().toISOString().split('T')[0],
        };
        // Add spec-specific fields
        if (spec.frontmatter.priority) {
            frontmatter.priority = spec.frontmatter.priority;
        }
        if (spec.frontmatter.status) {
            frontmatter.status = spec.frontmatter.status;
        }
        // Convert to YAML
        const yaml = Object.entries(frontmatter)
            .map(([key, value]) => {
            if (Array.isArray(value)) {
                return `${key}: [${value.map((v) => `"${v}"`).join(', ')}]`;
            }
            else if (typeof value === 'string') {
                return `${key}: "${value}"`;
            }
            else {
                return `${key}: ${value}`;
            }
        })
            .join('\n');
        return `---\n${yaml}\n---`;
    }
    /**
     * Generate description from sections
     */
    generateDescription(sections) {
        const firstSection = sections[0].section;
        const contentWithoutCode = firstSection.content.replace(/```[\s\S]*?```/g, '');
        const firstParagraph = contentWithoutCode.split('\n\n')[0];
        return firstParagraph.substring(0, 160).trim();
    }
    /**
     * Archive original spec for reference
     */
    async archiveOriginalSpec(incrementId, spec, project) {
        if (this.options.dryRun) {
            return;
        }
        const archivePath = path.join(this.options.basePath, 'specs', project.id, '_archive', `spec-${incrementId}.md`);
        await fs.ensureDir(path.dirname(archivePath));
        await fs.writeFile(archivePath, spec.raw, 'utf-8');
    }
    /**
     * Generate index file for a category
     */
    async generateIndex(category, projectId, files) {
        if (this.options.dryRun) {
            return;
        }
        const categoryPath = path.join(this.options.basePath, category === ContentCategory.UserStory || category === ContentCategory.NFR ? 'specs' : category, projectId);
        const indexPath = path.join(categoryPath, 'README.md');
        let content = `# ${this.getCategoryTitle(category)}\n\n`;
        content += `**Project**: ${projectId}\n`;
        content += `**Category**: ${category}\n`;
        content += `**Files**: ${files.length}\n\n`;
        content += `## Files\n\n`;
        for (const file of files.sort((a, b) => a.path.localeCompare(b.path))) {
            const filename = path.basename(file.path);
            const title = filename.replace(/\.md$/, '').replace(/-/g, ' ');
            content += `- [${title}](./${filename})\n`;
        }
        content += `\n---\n\n`;
        content += `Generated by SpecWeave Intelligent Living Docs Sync\n`;
        await fs.ensureDir(path.dirname(indexPath));
        await fs.writeFile(indexPath, content, 'utf-8');
    }
    /**
     * Get category display title
     */
    getCategoryTitle(category) {
        const titles = {
            [ContentCategory.UserStory]: 'User Stories',
            [ContentCategory.NFR]: 'Non-Functional Requirements',
            [ContentCategory.Architecture]: 'Architecture',
            [ContentCategory.ADR]: 'Architecture Decision Records',
            [ContentCategory.Operations]: 'Operations',
            [ContentCategory.Delivery]: 'Delivery',
            [ContentCategory.Strategy]: 'Strategy',
            [ContentCategory.Governance]: 'Governance',
            [ContentCategory.Overview]: 'Overview',
            [ContentCategory.Unknown]: 'Uncategorized',
        };
        return titles[category] || category;
    }
    /**
     * Get distribution statistics
     */
    getStatistics(result) {
        const allFiles = [...result.created, ...result.updated, ...result.skipped];
        const totalSize = allFiles.reduce((sum, f) => sum + f.size, 0);
        const byCategory = {};
        for (const file of allFiles) {
            if (!byCategory[file.category]) {
                byCategory[file.category] = { files: 0, size: 0 };
            }
            byCategory[file.category].files++;
            byCategory[file.category].size += file.size;
        }
        return {
            totalFiles: allFiles.length,
            totalSize,
            averageSize: totalSize / allFiles.length || 0,
            byCategory,
        };
    }
}
/**
 * Factory function to create distributor
 */
export function createContentDistributor(options) {
    return new ContentDistributor(options);
}
//# sourceMappingURL=content-distributor.js.map