/**
 * Paragraph Layout Module
 * Implements the Knuth and Plass line breaking algorithm for optimal typography
 * and connects it to the text rendering pipeline.
 */
import { BaseModule } from './base-module.js';

class ParagraphLayoutModule extends BaseModule {
    constructor() {
        super('paragraph-layout', 'Paragraph Layout');

        this.dependencies = ['text-processor'];

        this.ruler = null;
        this.rulerStack = [];

        this.updateConfig({
            maxLineWidth: 600,
            hyphenationEnabled: true,
            defaultFontSize: '1rem',
            defaultFontFamily: "'EB Garamond', serif",
            defaultLineHeight: 1.5,
            debugMode: false
        });

        this.bindMethods([
            'calculateLayout',
            'measureText',
            'setDebugMode',
            'updateFont',
            'processTextForLayout',
            'initializeTextMeasurement',
            'setupEventListeners',
            'loadLayoutDependencies'
        ]);
    }

    async initialize() {
        try {
            this.reportProgress(20, "Initializing paragraph layout");

            const textProcessor = this.getModule('text-processor');
            if (!textProcessor) {
                console.warn("Paragraph Layout: Text Processor not found, will use unprocessed text");
            }

            await this.loadLayoutDependencies();
            this.initializeTextMeasurement();
            this.setupEventListeners();

            this.reportProgress(100, "Paragraph layout ready");
            return true;
        } catch (error) {
            console.error("Error initializing Paragraph Layout:", error);
            return false;
        }
    }

    async loadLayoutDependencies() {
        try {
            this.reportProgress(30, "Loading layout dependencies");

            await this.loadScript('/js/linked-list.js');
            await this.loadScript('/js/linebreak.js');
            await this.loadScript('/js/knuth-and-plass.js');

            this.reportProgress(50, "Layout dependencies loaded");
            return true;
        } catch (error) {
            console.error("Error loading layout dependencies:", error);
            return false;
        }
    }

    initializeTextMeasurement() {
        let ruler = document.getElementById('ruler');

        if (!ruler) {
            ruler = document.createElement('span');
            ruler.id = 'ruler';
            document.body.appendChild(ruler);
        }

        Object.assign(ruler.style, {
            visibility: 'hidden',
            position: 'absolute',
            top: '-8000px',
            left: '-8000px',
            width: 'auto',
            display: 'inline',
            textIndent: '0',
            textAlign: 'left',
            hyphens: 'none',
            marginBlockEnd: '0'
        });

        this.ruler = ruler;
        this.rulerStack = [ruler];
        this.updateFont(this.config.defaultFontSize, this.config.defaultFontFamily);
    }

    setupEventListeners() {
        this.addEventListener(document, 'ui:font:change', (event) => {
            if (event.detail) {
                const { fontSize, fontFamily } = event.detail;
                if (fontSize || fontFamily) {
                    this.updateFont(
                        fontSize || this.config.defaultFontSize,
                        fontFamily || this.config.defaultFontFamily
                    );
                }
            }
        });

        this.addEventListener(document, 'ui:hyphenation:toggle', (event) => {
            if (event.detail && typeof event.detail.enabled === 'boolean') {
                this.updateConfig({ hyphenationEnabled: event.detail.enabled });
            }
        });
    }

    updateFont(fontSize, fontFamily) {
        if (!this.ruler) {
            console.warn("Text measurement ruler not initialized");
            return;
        }

        if (fontSize) this.updateConfig({ defaultFontSize: fontSize });
        if (fontFamily) this.updateConfig({ defaultFontFamily: fontFamily });

        this.ruler.style.fontSize = fontSize;
        this.ruler.style.fontFamily = fontFamily;
        this.ruler.style.fontFeatureSettings = "'kern' on, 'liga' on, 'onum' on, 'clig' on, 'hlig' on";

        if (this.config.debugMode) {
            console.log(`Font updated: ${fontSize} ${fontFamily}`);
        }
    }

    measureText(text) {
        if (!this.ruler) return 0;
        if (!text) return 0;

        if (text.substr(0, 2) === '</') {
            if (this.rulerStack.length > 1) {
                const child = this.rulerStack.pop();
                const parent = this.rulerStack[this.rulerStack.length - 1];
                if (child.parentElement === parent) {
                    parent.removeChild(child);
                }
            }
            return 0;
        }

        if (text.substr(0, 1) === '<') {
            const template = document.createElement('div');
            template.innerHTML = text;
            const child = template.firstChild;

            if (child) {
                const parent = this.rulerStack[this.rulerStack.length - 1];
                this.rulerStack.push(child);
                parent.appendChild(child);
            }

            return 0;
        }

        if (text === '|') return 0;
        if (text === ' ') text = '\u00A0';

        const parent = this.rulerStack[this.rulerStack.length - 1];
        const textNode = document.createTextNode(text);
        parent.appendChild(textNode);
        const rect = parent.getClientRects()[0] || parent.getBoundingClientRect();
        const width = rect ? rect.width : 0;
        parent.removeChild(textNode);

        return width;
    }

    processTextForLayout(text) {
        if (!text) return '';

        let processedText = text;
        const textProcessor = this.getModule('text-processor');

        if (textProcessor && typeof textProcessor.process === 'function') {
            processedText = textProcessor.process(processedText, {
                smartypants: true,
                hyphenate: this.config.hyphenationEnabled,
                hyphenSelector: '.hyphenatePipe'
            });
        } else if (this.config.debugMode) {
            console.log("Text processor not available, skipping text processing");
        }

        return processedText;
    }

    calculateLayout(text, options = {}) {
        if (!text) return null;

        try {
            if (typeof window.kap !== 'function') {
                console.error("Paragraph Layout: kap function not available. Make sure knuth-and-plass.js is loaded.");
                return null;
            }

            const processedText = this.processTextForLayout(text);
            const layoutOptions = {
                width: options.width || this.config.maxLineWidth,
                fontSize: options.fontSize || this.config.defaultFontSize,
                fontFamily: options.fontFamily || this.config.defaultFontFamily,
                lineHeight: options.lineHeight || this.config.defaultLineHeight,
                lineHeightPx: options.lineHeightPx,
                tolerance: options.tolerance || 3,
                demerits: options.demerits || {
                    line: 10,
                    flagged: 100,
                    fitness: 3000
                }
            };

            this.updateFont(layoutOptions.fontSize, layoutOptions.fontFamily);
            const numericFontSize = parseFloat(layoutOptions.fontSize) || 16;
            const lineHeightPx = layoutOptions.lineHeightPx || (numericFontSize * layoutOptions.lineHeight);

            const measure = options.measures || [layoutOptions.width];

            if (this.config.debugMode) {
                console.log("Paragraph Layout: Calculating layout for text", {
                    text: processedText,
                    measure,
                    options: layoutOptions
                });
            }

            const layout = window.kap(
                processedText,
                this.measureText.bind(this),
                measure,
                this.config.hyphenationEnabled,
                layoutOptions.tolerance,
                layoutOptions.demerits
            );

            if (!layout || !layout.breaks || !layout.nodes) {
                console.warn("Paragraph Layout: Failed to calculate layout for text");
                return null;
            }

            if (this.config.debugMode) {
                console.log("Paragraph Layout: Layout calculated", {
                    breaks: layout.breaks.length,
                    nodes: layout.nodes.length
                });
            }

            return {
                ...layout,
                originalText: text,
                processedText,
                width: layoutOptions.width,
                lineHeight: layoutOptions.lineHeight,
                lineHeightPx,
                fontSize: layoutOptions.fontSize,
                fontFamily: layoutOptions.fontFamily
            };
        } catch (error) {
            console.error("Error calculating layout:", error);
            return null;
        }
    }

    setDebugMode(enabled) {
        this.updateConfig({ debugMode: enabled });
        console.log(`Paragraph Layout: Debug mode ${enabled ? 'enabled' : 'disabled'}`);
    }
}

const ParagraphLayout = new ParagraphLayoutModule();

if (window.moduleRegistry) {
    window.moduleRegistry.register(ParagraphLayout);
}

export { ParagraphLayout };

window.ParagraphLayout = ParagraphLayout;
