import blessed from 'blessed';

/**
 * TUI pour le browser de guides développeur.
 *
 * Layout :
 *   ┌─ header ──────────────────────────────────────────────────────────┐
 *   │ Guides (35%)                  │ Content (65%)                     │
 *   │                               │                                   │
 *   ├───────────────────────────────┴───────────────────────────────────┤
 *   │ ↑↓ navigate  / filter  Tab switch pane  q quit                   │
 *   │ / <filter>                                                        │
 *   └───────────────────────────────────────────────────────────────────┘
 *
 * Touches :
 *   ↑ / ↓       naviguer dans la liste (prévisualisation automatique)
 *   Enter       sélectionner (focus le panneau content)
 *   /           ouvrir le filtre (affiner la liste)
 *   Escape      vider le filtre / revenir à la liste
 *   Tab         basculer entre la liste et le panneau content
 *   q / Ctrl+C  quitter
 */
export class GuideBrowser {
    constructor({ screen, sections, guideTitles, initialQuery = '' }) {
        this.screen = screen;
        this.allSections = sections;
        this.guideTitles = guideTitles;
        this.filteredSections = [...sections];
        this.listMap = []; // index de liste → index dans filteredSections (null = en-tête guide)

        this._build();
        this._bindKeys();
        this._rebuildList();

        if (initialQuery) {
            this.filterInput.setValue(initialQuery);
            this._applyFilter(initialQuery);
        } else if (this.filteredSections.length) {
            this._showContent(0);
        }
    }

    _build() {
        const screen = this.screen;

        this.header = blessed.box({
            parent: screen,
            top: 0, left: 0, width: '100%', height: 1,
            content: ' {bold}Developer Guides Browser{/bold}',
            tags: true,
            style: { bg: 'blue', fg: 'white' }
        });

        this.sectionList = blessed.list({
            parent: screen,
            label: ' Guides ',
            top: 1, left: 0, width: '35%', height: screen.height - 3,
            border: { type: 'line' },
            scrollable: true, alwaysScroll: true, mouse: true,
            keys: true, vi: true,
            tags: true,
            style: {
                border: { fg: 'cyan' },
                focus: { border: { fg: 'yellow' } },
                selected: { bg: 'blue', fg: 'white' }
            },
            items: []
        });

        this.contentBox = blessed.box({
            parent: screen,
            label: ' Content ',
            top: 1, left: '35%', width: '65%', height: screen.height - 3,
            border: { type: 'line' },
            scrollable: true, alwaysScroll: true, mouse: true,
            keys: true, vi: true,
            tags: true,
            style: {
                border: { fg: 'cyan' },
                focus: { border: { fg: 'yellow' } }
            }
        });

        this.hints = blessed.box({
            parent: screen,
            top: screen.height - 2, left: 0, width: '100%', height: 1,
            content: ' {bold}↑↓{/bold} navigate  {bold}/{/bold} filter  {bold}Tab{/bold} switch pane  {bold}Esc{/bold} clear filter  {bold}q{/bold} quit',
            tags: true,
            style: { bg: 'black', fg: 'white' }
        });

        this.filterInput = blessed.textbox({
            parent: screen,
            top: screen.height - 1, left: 0, width: '100%', height: 1,
            mouse: true,
            style: { fg: 'white', bg: 'black', focus: { bg: '#111' } }
        });

        // Prévisualisation automatique lors de la navigation
        this.sectionList.on('select item', (_item, idx) => {
            this._showContent(idx);
        });

        // Enter dans la liste → focus le panneau content
        this.sectionList.on('select', () => {
            this.contentBox.focus();
            screen.render();
        });

        this.sectionList.focus();
        screen.render();
    }

    _bindKeys() {
        const screen = this.screen;

        screen.key(['q', 'C-c'], () => {
            this._confirmQuit();
        });

        screen.key('/', () => {
            if (screen.focused === this.filterInput) return;
            this._startFilter();
        });

        screen.key('escape', () => {
            if (screen.focused === this.filterInput) {
                this.filterInput.clearValue();
                this._applyFilter('');
                this.sectionList.focus();
                screen.render();
            } else if (screen.focused === this.contentBox) {
                this.sectionList.focus();
                screen.render();
            }
        });

        screen.key('tab', () => {
            if (screen.focused === this.sectionList) {
                this.contentBox.focus();
            } else {
                this.sectionList.focus();
            }
            screen.render();
        });

        this.filterInput.on('submit', (value) => {
            this._applyFilter(value || '');
            this.sectionList.focus();
            screen.render();
        });

        this.filterInput.on('cancel', () => {
            this.filterInput.clearValue();
            this._applyFilter('');
            this.sectionList.focus();
            screen.render();
        });
    }

    _confirmQuit() {
        const box = blessed.box({
            parent:  this.screen,
            top:     'center',
            left:    'center',
            width:   36,
            height:  5,
            tags:    true,
            border:  { type: 'line' },
            style:   { fg: 'white', bg: 'black', border: { fg: 'yellow' } },
            label:   ' Quitter ',
            content: '\n  Quitter le browser ?  {bold}o{/bold} / {bold}n{/bold}',
        });

        const close = () => { box.destroy(); this.screen.render(); };

        box.key(['o', 'O', 'y', 'Y', 'enter'], () => { close(); process.exit(0); });
        box.key(['n', 'N', 'escape', 'q'],       () => { close(); });

        box.focus();
        this.screen.render();
    }

    _startFilter() {
        this.filterInput.focus();
        this.filterInput.readInput(() => {});
        this.screen.render();
    }

    _applyFilter(query) {
        const q = query.toLowerCase().trim();

        if (!q) {
            this.filteredSections = [...this.allSections];
        } else {
            const tokens = q.split(/\s+/).filter(t => t.length > 0);
            this.filteredSections = this.allSections.filter(sec =>
                tokens.every(t => sec.searchText.includes(t))
            );
        }

        this._rebuildList();

        if (this.filteredSections.length > 0) {
            this._showContent(0);
        } else {
            this.contentBox.setContent('  {grey-fg}No results.{/grey-fg}');
            this.screen.render();
        }
    }

    _rebuildList() {
        const items = [];
        this.listMap = [];

        let currentGuide = null;

        for (let i = 0; i < this.filteredSections.length; i++) {
            const sec = this.filteredSections[i];

            if (sec.guide !== currentGuide) {
                currentGuide = sec.guide;
                const title = sec.guideTitle || sec.guide;
                items.push(`{bold}{cyan-fg}${_esc(title)}{/cyan-fg}{/bold}`);
                this.listMap.push(null); // en-tête guide
            }

            const indent = sec.level === 3 ? '      ' : '  ';
            const prefix = sec.level === 3 ? '{grey-fg}─{/grey-fg} ' : '{grey-fg}──{/grey-fg} ';
            items.push(`${indent}${prefix}${_esc(sec.section)}`);
            this.listMap.push(i);
        }

        this.sectionList.setItems(items.length ? items : ['{grey-fg}(no results){/grey-fg}']);
        this.sectionList.select(0);
        this.screen.render();
    }

    _showContent(listIdx) {
        const sectionIdx = this.listMap[listIdx];

        if (sectionIdx === null || sectionIdx === undefined) {
            // En-tête de guide — afficher la première section du guide
            for (let i = listIdx + 1; i < this.listMap.length; i++) {
                if (this.listMap[i] !== null) {
                    this._renderSection(this.filteredSections[this.listMap[i]]);
                    return;
                }
            }
            return;
        }

        const sec = this.filteredSections[sectionIdx];
        if (sec) this._renderSection(sec);
    }

    _renderSection(sec) {
        const headerMark = sec.level === 3 ? '###' : '##';
        const guideLabel = `{grey-fg}${_esc(sec.guideTitle || sec.guide)}{/grey-fg}`;
        const sectionHeader = `{bold}{yellow-fg}${_esc(headerMark + ' ' + sec.section)}{/yellow-fg}{/bold}`;
        const body = _renderMarkdown(sec.content);

        this.contentBox.setContent(`${guideLabel}\n\n${sectionHeader}\n\n${body}`);
        this.contentBox.scrollTo(0);
        this.screen.render();
    }
}

function _esc(str) {
    return String(str).replace(/[{}]/g, c => c === '{' ? '\\{' : '\\}');
}

function _inline(text) {
    const e = _esc(text);
    return e
        .replace(/`([^`]+)`/g, (_, c) => `{cyan-fg}${c}{/cyan-fg}`)
        .replace(/\*\*\*(.+?)\*\*\*/g, (_, t) => `{bold}{underline}${t}{/underline}{/bold}`)
        .replace(/\*\*(.+?)\*\*/g, (_, t) => `{bold}${t}{/bold}`)
        .replace(/\*([^*\n]+)\*/g, (_, t) => `{grey-fg}${t}{/grey-fg}`)
        .replace(/\b_([^_\n]+)_\b/g, (_, t) => `{grey-fg}${t}{/grey-fg}`)
        .replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, t, u) => `{blue-fg}{underline}${t}{/underline}{/blue-fg} {grey-fg}(${_esc(u)}){/grey-fg}`);
}

function _renderMarkdown(content) {
    const lines = content.split('\n');
    const out = [];
    let inCode = false;
    let codeBuf = [];
    let codeLang = '';
    let tableBuf = [];

    // Mesure la largeur visuelle en retirant les tags blessed et les codes ANSI
    const stripTags = s => s.replace(/\{[^}]+\}/g, '').replace(/\x1b\[[0-9;]*m/g, '');

    const flushCode = () => {
        const langLabel = codeLang ? ` {yellow-fg}${_esc(codeLang)}{/yellow-fg}` : '';
        out.push(`{grey-fg}  ┌${'─'.repeat(54)}{/grey-fg}${langLabel}`);
        // ANSI bruts pour éviter l'échappement blessed des accolades JSON
        for (const cl of codeBuf) out.push(`\x1b[90m  │ \x1b[0m\x1b[36m${cl}\x1b[0m`);
        out.push(`{grey-fg}  └${'─'.repeat(54)}{/grey-fg}`);
        codeBuf = [];
        codeLang = '';
    };

    const flushTable = () => {
        if (!tableBuf.length) return;

        const allRows = tableBuf.map(row => {
            const isSep = /^\|[-| :]+\|$/.test(row);
            return { isSep, cells: isSep ? null : row.split('|').slice(1, -1).map(c => c.trim()) };
        });

        const dataRows = allRows.filter(r => !r.isSep).map(r => r.cells);
        const numCols = dataRows.length ? Math.max(...dataRows.map(r => r.length)) : 0;
        const maxWidths = Array(numCols).fill(0);

        for (const cells of dataRows) {
            for (let i = 0; i < Math.min(cells.length, numCols); i++) {
                maxWidths[i] = Math.max(maxWidths[i], stripTags(_inline(cells[i])).length);
            }
        }

        for (const { isSep, cells } of allRows) {
            if (isSep) {
                const total = maxWidths.reduce((a, b) => a + b, 0) + Math.max(numCols - 1, 0) * 5;
                out.push(`{grey-fg}  ${'─'.repeat(Math.max(total, 0))}{/grey-fg}`);
            } else {
                const rendered = cells.map((c, i) => {
                    const r = _inline(c);
                    const pad = (maxWidths[i] || 0) - stripTags(r).length;
                    return r + ' '.repeat(Math.max(0, pad));
                });
                out.push('  ' + rendered.join('{grey-fg}  │  {/grey-fg}'));
            }
        }

        tableBuf = [];
    };

    for (const line of lines) {
        // Vider le buffer de table si la ligne courante n'est pas une ligne de tableau
        if (!line.startsWith('|') && tableBuf.length) flushTable();

        // --- Blocs de code ---
        if (line.startsWith('```')) {
            if (!inCode) { inCode = true; codeLang = line.slice(3).trim(); }
            else { inCode = false; flushCode(); }
            continue;
        }
        if (inCode) { codeBuf.push(line); continue; }

        // --- Titres ---
        const h1 = line.match(/^# (.+)/);
        const h2 = line.match(/^## (.+)/);
        const h3 = line.match(/^### (.+)/);
        if (h1) {
            const t = _esc(h1[1]);
            out.push('', `{bold}{underline}{white-fg}${t}{/white-fg}{/underline}{/bold}`,
                `{grey-fg}${'═'.repeat(Math.min(h1[1].length, 60))}{/grey-fg}`, '');
            continue;
        }
        if (h2) { out.push('', `{bold}{yellow-fg}${_inline(h2[1])}{/yellow-fg}{/bold}`, ''); continue; }
        if (h3) { out.push('', `{bold}${_inline(h3[1])}{/bold}`); continue; }

        // --- Ligne horizontale ---
        if (line.match(/^---+$/)) { out.push(`{grey-fg}${'─'.repeat(60)}{/grey-fg}`); continue; }

        // --- Blockquote ---
        if (line.startsWith('> ')) {
            out.push(`{grey-fg}  │ ${_inline(line.slice(2))}{/grey-fg}`);
            continue;
        }

        // --- Checklist ---
        const ck = line.match(/^- \[( |x)\] (.+)/i);
        if (ck) {
            const done = ck[1].toLowerCase() === 'x';
            const box = done ? '{green-fg}☑{/green-fg}' : '{grey-fg}☐{/grey-fg}';
            out.push(`  ${box} ${done ? `{grey-fg}${_inline(ck[2])}{/grey-fg}` : _inline(ck[2])}`);
            continue;
        }

        // --- Listes à puces ---
        const ul = line.match(/^(\s*)[*\-+] (.+)/);
        if (ul) {
            const depth = ul[1].length;
            const bullet = depth > 0 ? '{grey-fg}◦{/grey-fg}' : '{yellow-fg}•{/yellow-fg}';
            out.push(`${' '.repeat(depth + 2)}${bullet} ${_inline(ul[2])}`);
            continue;
        }

        // --- Listes numérotées ---
        const ol = line.match(/^(\s*)(\d+)\. (.+)/);
        if (ol) {
            out.push(`${' '.repeat(ol[1].length + 2)}{yellow-fg}${ol[2]}.{/yellow-fg} ${_inline(ol[3])}`);
            continue;
        }

        // --- Table (buffering pour alignement) ---
        if (line.startsWith('|')) {
            tableBuf.push(line);
            continue;
        }

        // --- Ligne vide / texte normal ---
        out.push(line.trim() === '' ? '' : _inline(line));
    }

    if (tableBuf.length) flushTable();
    if (inCode) flushCode();
    return out.join('\n');
}
