/**
 * Text Processor Module
 * Handles text formatting and typography enhancements like smart quotes and hyphenation
 */
import { BaseModule } from './base-module.js';

class TextProcessorModule extends BaseModule {
    constructor() {
        super('text-processor', 'Text Processor');
        this.smartyPants = null;
        this.smartypantsu = null;
        this.hyphenator = null;
        this.hyphenatorReady = false;
        this.locale = 'en-us';
        
        this.dependencies = ['localization', 'game-config'];
        
        // Bind methods using parent's bindMethods utility
        this.bindMethods([
            'loadSmartyPantsScript',
            'initializeHyphenation',
            'process',
            'isHyphenationAvailable',
            'hyphenate',
            'setLocale',
            'loadHyphenopolyLoader',
            'normalizeHyphenationLocale',
            'applyLocaleTypography',
            'getTypographyLocale',
            'normalizeDialogueQuotes'
        ]);
    }

    /**
     * Initialize the module
     * @returns {Promise<boolean>} - Resolves with success status
     */
    async initialize() {
        try {
            this.reportProgress(10, "Initializing text processor");

            const gameConfig = this.getModule('game-config');
            this.locale = gameConfig?.getLocale?.() || 'en_US';

            this.addEventListener(document, 'game:config', (event) => {
                const gameLocale = event.detail?.metadata?.language || event.detail?.locale;
                if (gameLocale) {
                    this.setLocale(gameLocale);
                }
            });
            
            this.reportProgress(30, `Locale set to ${this.locale}`);

            // Ensure global locale is set for SmartyPants
            window.locale = this.locale;
            
            // Load SmartyPants - critical dependency
            this.reportProgress(40, "Loading SmartyPants");
            try {
                await this.loadSmartyPantsScript();
                
                // Verify SmartyPants is properly loaded
                if (!this.smartyPants || typeof this.smartyPants !== 'function') {
                    throw new Error('SmartyPants not properly loaded');
                }
                
                this.reportProgress(70, "SmartyPants loaded successfully");
            } catch (error) {
                console.error("Failed to load SmartyPants:", error);
                this.reportProgress(100, "Text processor initialization failed - SmartyPants not available");
                return false;
            }
            
            // Initialize hyphenation (non-critical)
            this.reportProgress(80, "Initializing hyphenation");
            try {
                await this.initializeHyphenation();
                this.reportProgress(100, "Text processor ready");
                return true;
            } catch (error) {
                console.warn("Failed to initialize hyphenation:", error);
                // Continue without hyphenation, still mark as successful
                this.reportProgress(100, "Text processor ready (without hyphenation)");
                return true;
            }
        } catch (error) {
            console.error("Error initializing text processor:", error);
            this.reportProgress(100, "Text processor initialization failed");
            return false;
        }
    }

    /**
     * Set the locale for the text processor
     * @param {string} locale - The locale to set
     */
    setLocale(locale) {
        this.locale = locale;
        console.log(`Text processor locale set to ${locale}`);
        
        // Reinitialize hyphenation with new locale if needed
        if (this.hyphenatorReady) {
            this.initializeHyphenation();
        }
    }

    /**
     * Load the SmartyPants script dynamically and wait for it to be ready
     * @returns {Promise<void>}
     */
    loadSmartyPantsScript() {
        return new Promise((resolve, reject) => {
            // Check if already loaded globally
            if (typeof window.SmartyPants === 'object' && typeof window.SmartyPants.smartypants === 'function') {
                this.smartyPants = window.SmartyPants.smartypants;
                this.smartypantsu = window.SmartyPants.smartypantsu;
                console.log("SmartyPants already loaded globally");
                resolve();
                return;
            }
            
            // Create script element
            const script = document.createElement('script');
            script.type = 'text/javascript';
            script.src = '/js/smartypants.js'; // Use relative URL
            script.async = true;
            
            // Set up load and error handlers
            script.onload = () => {
                if (typeof window.SmartyPants === 'object' && typeof window.SmartyPants.smartypants === 'function') {
                    this.smartyPants = window.SmartyPants.smartypants;
                    this.smartypantsu = window.SmartyPants.smartypantsu;
                    console.log("SmartyPants loaded successfully");
                    resolve();
                } else {
                    const error = new Error('SmartyPants loaded but functions not found');
                    console.error(error);
                    reject(error);
                }
            };
            
            script.onerror = (error) => {
                console.error("Error loading SmartyPants script:", error);
                reject(new Error('Failed to load SmartyPants script'));
            };
            
            // Add script to document
            document.head.appendChild(script);
        });
    }

    /**
     * Initialize hyphenation using the browser Hyphenopoly loader used by the prototype.
     * @returns {Promise<boolean>} - Resolves when hyphenation is initialized
     */
    async initializeHyphenation() {
        try {
            console.log("Initializing hyphenation with browser Hyphenopoly loader");

            const locale = this.normalizeHyphenationLocale(this.locale);
            this.hyphenator = null;
            this.hyphenatorReady = false;

            await this.loadHyphenopolyLoader();

            window.Hyphenopoly.config({
                require: {
                    [locale]: "FORCEHYPHENOPOLY"
                },
                paths: {
                    maindir: "/js/",
                    patterndir: "/js/patterns/"
                },
                setup: {
                    hide: "element",
                    selectors: {
                        ".hyphenate": { hyphen: "\u00AD" },
                        ".hyphenatePipe": { hyphen: "|" }
                    }
                },
                handleEvent: {
                    error: (event) => {
                        console.warn(`Hyphenopoly error: ${event.msg || event.message || event.type}`);
                    },
                    engineReady: (event) => {
                        console.log(`Hyphenopoly engine ready: ${event.msg || locale}`);
                    }
                }
            });

            this.hyphenator = await window.Hyphenopoly.hyphenators[locale];
            this.hyphenatorReady = true;
            this.locale = locale;

            console.log(`Hyphenator ready for ${locale}`);
            document.dispatchEvent(new CustomEvent('hyphenation-loaded'));
            return true;
        } catch (error) {
            this.hyphenator = null;
            this.hyphenatorReady = false;
            console.error("Failed to initialize Hyphenopoly browser hyphenation:", error);
            throw error;
        }
    }

    loadHyphenopolyLoader() {
        return new Promise((resolve, reject) => {
            if (window.Hyphenopoly && typeof window.Hyphenopoly.config === 'function') {
                resolve();
                return;
            }

            const existingScript = document.querySelector('script[src="/js/Hyphenopoly_Loader.js"]');
            if (existingScript) {
                existingScript.addEventListener('load', () => resolve(), { once: true });
                existingScript.addEventListener('error', () => reject(new Error('Failed to load Hyphenopoly loader')), { once: true });
                return;
            }

            const script = document.createElement('script');
            script.src = '/js/Hyphenopoly_Loader.js';
            script.async = true;
            script.onload = () => resolve();
            script.onerror = () => reject(new Error('Failed to load Hyphenopoly loader'));
            document.head.appendChild(script);
        });
    }

    normalizeHyphenationLocale(locale) {
        const normalized = String(locale || 'en-us').trim().toLowerCase().replace('_', '-');
        if (normalized === 'en') return 'en-us';
        if (normalized === 'de-de') return 'de';
        return normalized;
    }

    /**
     * Check if hyphenation is available
     * @returns {boolean} - True if hyphenation is available
     */
    isHyphenationAvailable() {
        return this.hyphenatorReady && this.hyphenator !== null;
    }

    /**
     * Hyphenate a text using the Hyphenopoly module
     * @param {string} text - The text to hyphenate
     * @param {string} selector - Optional selector for Hyphenopoly
     * @returns {string} - The hyphenated text
     */
    hyphenate(text, selector = null) {
        if (!this.isHyphenationAvailable()) {
            return text;
        }

        try {
            // If selector provided, pass it to hyphenator
            return selector ? this.hyphenator(text, selector) : this.hyphenator(text);
        } catch (error) {
            console.error("Error hyphenating text:", error);
            return text;
        }
    }

    /**
     * Process text with typography enhancements
     * @param {string} text - The text to process
     * @param {Object} options - Processing options
     * @param {boolean} [options.smartypants=true] - Whether to apply SmartyPants processing
     * @param {boolean} [options.hyphenate=true] - Whether to apply hyphenation
     * @param {string} [options.hyphenSelector=null] - Selector for hyphen character (e.g., '.hyphenatePipe')
     * @returns {string} - The processed text
     */
    process(text, options = {}) {
        const opts = {
            smartypants: true,
            hyphenate: true,
            hyphenSelector: null,
            ...options
        };

        let result = text;

        // Apply SmartyPants if available and requested
        if (opts.smartypants && this.smartypantsu) {
            result = this.smartypantsu(result, 1);
        } else if (opts.smartypants && this.smartyPants) {
            result = this.smartyPants(result);
        }

        if (opts.smartypants) {
            result = this.applyLocaleTypography(result);
        }

        // Apply hyphenation if available and requested
        if (opts.hyphenate && this.isHyphenationAvailable()) {
            result = this.hyphenate(result, opts.hyphenSelector);
        }

        return result;
    }

    applyLocaleTypography(text) {
        const locale = this.getTypographyLocale();
        if (locale.startsWith('de')) {
            return this.normalizeDialogueQuotes(text);
        }

        return text;
    }

    getTypographyLocale() {
        return String(this.locale || 'en_US').trim().toLowerCase().replace('_', '-');
    }

    normalizeDialogueQuotes(text) {
        return String(text || '')
            .replace(/&(ldquo|bdquo|laquo|raquo);([^&\n]+?)&(rdquo|ldquo|laquo|raquo);/gi, '»$2«')
            .replace(/["\u201c\u201e\u201d\u00ab\u00bb]([^"\u201c\u201e\u201d\u00ab\u00bb\n]+?)["\u201c\u201d\u201e\u00ab\u00bb]/g, '»$1«');
    }
}

// Create the singleton instance
const TextProcessor = new TextProcessorModule();

// Export the module
export { TextProcessor };
