import fs from 'fs/promises';
import path from 'path';
import chalk from 'chalk';
import { renderMarkdown as _renderMarkdown, renderInline as _inline } from '../output/markdown.js';

/**
 * Service Guides — charge et indexe les fichiers Markdown du répertoire guides/
 * pour permettre la navigation et la recherche dans la documentation développeur.
 */
export class Guides {
    constructor(program, logger, services) {
        this.logger = logger;
        this.services = services;
        services['guides'] = this;

        // Sections indexées : { guide, guideTitle, section, level, content, searchText }
        this.sections = [];
        // Titre H1 de chaque guide (nom de fichier sans .md → titre)
        this.guideTitles = {};

        const cmd = program
            .command('guides')
            .description('Browse and search developer guides');

        cmd.command('list')
            .description('List all available guides and their sections')
            .action(() => this._cmdList());

        cmd.command('search')
            .argument('<query...>', 'keywords to search for')
            .option('-l, --limit <n>', 'max results to return', '20')
            .description('Search across all developer guides')
            .action((query, options) => this._cmdSearch(query.join(' '), options));

        cmd.command('show')
            .argument('<guide>', 'guide name (partial match, e.g. "ucs", "webhook", "room")')
            .option('-s, --section <section>', 'show a specific section (partial match)')
            .description('Show a developer guide or a specific section')
            .action((guide, options) => this._cmdShow(guide, options));

        cmd.command('browse')
            .argument('[query]', 'optional initial search filter')
            .description('Interactive TUI browser for developer guides')
            .action(async (query) => this._cmdBrowse(query));
    }

    // --- Chargement ---

    async load(guidesDir) {
        this.logger.debug(`Guides.load: ${guidesDir}`);

        let files;
        try {
            files = await fs.readdir(guidesDir);
        } catch {
            this.logger.warn(`Guides: répertoire guides/ introuvable (${guidesDir})`);
            return;
        }

        const mdFiles = files.filter(f => f.endsWith('.md')).sort();

        for (const file of mdFiles) {
            const guideName = path.basename(file, '.md');
            try {
                const content = await fs.readFile(path.join(guidesDir, file), 'utf-8');
                const parsed = this._parseMarkdown(guideName, content);
                this.guideTitles[guideName] = parsed.title;
                this.sections.push(...parsed.sections);
            } catch (err) {
                this.logger.warn(`Guides: impossible de charger ${file}: ${err.message}`);
            }
        }

        this.logger.debug(`Guides: ${this.sections.length} sections chargées dans ${mdFiles.length} guides`);
    }

    _parseMarkdown(guideName, content) {
        const lines = content.split('\n');
        let title = guideName;
        const sections = [];

        let currentTitle = null;
        let currentLevel = 0;
        let currentLines = [];

        const flush = () => {
            if (currentTitle !== null) {
                const sectionContent = currentLines.join('\n').trim();
                sections.push({
                    guide: guideName,
                    guideTitle: title,
                    section: currentTitle,
                    level: currentLevel,
                    content: sectionContent,
                    searchText: (guideName + ' ' + title + ' ' + currentTitle + ' ' + sectionContent).toLowerCase()
                });
                currentLines = [];
            }
        };

        for (const line of lines) {
            const h1 = line.match(/^# (.+)/);
            const h2 = line.match(/^## (.+)/);
            const h3 = line.match(/^### (.+)/);

            if (h1) {
                title = h1[1];
            } else if (h2) {
                flush();
                currentTitle = h2[1];
                currentLevel = 2;
            } else if (h3) {
                flush();
                currentTitle = h3[1];
                currentLevel = 3;
            } else {
                currentLines.push(line);
            }
        }
        flush();

        return { title, sections };
    }

    // --- Recherche ---

    search(query, limit = 20) {
        const tokens = query.toLowerCase().split(/\s+/).filter(t => t.length > 1);
        if (!tokens.length) return [];

        const scored = [];
        for (const sec of this.sections) {
            let score = 0;
            for (const t of tokens) {
                if (sec.section.toLowerCase().includes(t)) score += 3;
                if (sec.guideTitle.toLowerCase().includes(t)) score += 2;
                if (sec.guide.toLowerCase().includes(t)) score += 1;
                if (sec.content.toLowerCase().includes(t)) score += 1;
            }
            if (score > 0) scored.push({ ...sec, score });
        }

        scored.sort((a, b) => b.score - a.score);
        return scored.slice(0, limit);
    }

    _findGuide(query) {
        const q = query.toLowerCase();
        const names = Object.keys(this.guideTitles);
        return names.find(n => n.toLowerCase().includes(q) || (this.guideTitles[n] || '').toLowerCase().includes(q));
    }

    // --- Commandes CLI ---

    _cmdList() {
        if (!this.sections.length) {
            console.log(chalk.yellow('No guides loaded. Place .md files in the guides/ directory.'));
            return;
        }

        const byGuide = {};
        for (const sec of this.sections) {
            if (!byGuide[sec.guide]) byGuide[sec.guide] = [];
            byGuide[sec.guide].push(sec);
        }

        console.log('');
        for (const [guide, secs] of Object.entries(byGuide)) {
            const title = this.guideTitles[guide] || guide;
            console.log(`  ${chalk.bold.cyan(title)}`);
            console.log(`  ${chalk.dim(guide + '.md')}`);
            for (const sec of secs) {
                const indent = sec.level === 3 ? '        ' : '    ';
                const prefix = sec.level === 3 ? '─ ' : '── ';
                console.log(`  ${indent}${chalk.dim(prefix)}${sec.section}`);
            }
            console.log('');
        }
    }

    _cmdSearch(query, options) {
        if (!this.sections.length) {
            console.log(chalk.yellow('No guides loaded.'));
            return;
        }

        const limit = parseInt(options.limit) || 20;
        const results = this.search(query, limit);

        if (!results.length) {
            console.log(chalk.yellow(`No sections matching "${query}".`));
            return;
        }

        const tokens = query.toLowerCase().split(/\s+/).filter(t => t.length > 1);

        console.log('');
        for (const r of results) {
            const headerMark = r.level === 3 ? '###' : '##';
            console.log(`  ${chalk.bold.cyan(r.guideTitle)}`);
            console.log(`  ${chalk.bold(headerMark + ' ' + r.section)}`);

            // Montrer les premières lignes contenant un token
            const contentLines = r.content.split('\n');
            let shown = 0;
            for (const line of contentLines) {
                if (line.startsWith('```') || line.startsWith('#')) continue;
                const ll = line.toLowerCase();
                if (tokens.some(t => ll.includes(t)) && line.trim()) {
                    const display = line.length > 120 ? line.substring(0, 120) + '…' : line;
                    console.log(`  ${chalk.dim(display)}`);
                    if (++shown >= 3) break;
                }
            }
            console.log('');
        }

        if (results.length === limit) {
            console.log(chalk.dim(`  Showing ${limit} results. Use --limit to see more.`));
            console.log('');
        }
    }

    _cmdShow(guideQuery, options) {
        const guide = this._findGuide(guideQuery);

        if (!guide) {
            console.log(chalk.red(`No guide matching "${guideQuery}".`));
            const names = Object.keys(this.guideTitles);
            if (names.length) {
                console.log(chalk.dim(`Available: ${names.join(', ')}`));
            }
            return;
        }

        const guideSections = this.sections.filter(s => s.guide === guide);

        const toShow = options.section
            ? guideSections.filter(s => s.section.toLowerCase().includes(options.section.toLowerCase()))
            : guideSections;

        if (!toShow.length) {
            console.log(chalk.yellow(`No section matching "${options.section}" in this guide.`));
            return;
        }

        if (!options.section) {
            const title = this.guideTitles[guide] || guide;
            console.log(_renderMarkdown(`# ${title}`));
        }

        for (const sec of toShow) {
            const headerMark = '#'.repeat(sec.level);
            console.log(_renderMarkdown(`${headerMark} ${sec.section}\n\n${sec.content}`));
        }
    }

    async _cmdBrowse(initialQuery) {
        if (!this.sections.length) {
            console.log(chalk.yellow('No guides loaded. Place .md files in the guides/ directory.'));
            return;
        }

        const blessed = (await import('blessed')).default;
        const { GuideBrowser } = await import('../output/GuideBrowser.js');

        const screen = blessed.screen({ smartCSR: true, title: 'Developer Guides Browser' });

        new GuideBrowser({
            screen,
            sections: this.sections,
            guideTitles: this.guideTitles,
            initialQuery: initialQuery || ''
        });

        screen.render();
    }
}
