/**
 * Choice Display Module
 * Renders choice-mode interactions from TurnResult choices.
 */
import { BaseModule } from './base-module.js';

class ChoiceDisplayModule extends BaseModule {
    constructor() {
        super('choice-display', 'Choice Display');

        this.dependencies = ['socket-client', 'markup-parser'];
        this.socketClient = null;
        this.markupParser = null;
        this.container = null;
        this.choices = [];
        this.inputMode = 'text';
        this.processState = document.documentElement.dataset.processState || 'loading';
        this.template = {
            cells: {
                default: {
                    label: '',
                    match: () => true
                }
            },
            fallbackCell: 'default'
        };

        this.bindMethods([
            'initialize',
            'setupContainer',
            'handleChoices',
            'handleInputMode',
            'handleProcessState',
            'handleKeyDown',
            'render',
            'clear',
            'normalizeChoices',
            'assignLetters',
            'selectChoice',
            'getTagValue',
            'getTemplateCell',
            'renderChoiceText'
        ]);
    }

    async initialize() {
        this.socketClient = this.getModule('socket-client');
        this.markupParser = this.getModule('markup-parser');
        this.setupContainer();

        this.addEventListener(document, 'story:choices', (event) => {
            this.handleChoices(event.detail || []);
        });
        this.addEventListener(document, 'story:input-mode', (event) => {
            this.handleInputMode(event.detail || 'text');
        });
        this.addEventListener(document, 'story:process-state', (event) => {
            this.handleProcessState(event.detail?.state || 'ready');
        });
        this.addEventListener(document, 'story:turn-start', () => {
            this.processState = 'waiting-generating';
            this.render();
        });
        this.addEventListener(document, 'story:history-restoring', (event) => {
            document.documentElement.dataset.historyRestoring = event.detail?.active ? 'true' : 'false';
            this.render();
        });
        this.addEventListener(document, 'keydown', this.handleKeyDown);

        this.reportProgress(100, 'Choice display ready');
        return true;
    }

    setupContainer() {
        const choicesRoot = document.getElementById('choices');
        if (!choicesRoot) {
            return;
        }

        this.container = document.getElementById('story_choices');
        if (!this.container) {
            this.container = document.createElement('div');
            this.container.id = 'story_choices';
            this.container.className = 'story-choices';
        }

        const commandInput = document.getElementById('command_input');
        if (this.container.parentElement !== choicesRoot) {
            choicesRoot.insertBefore(this.container, commandInput || null);
        } else if (commandInput && this.container.nextElementSibling !== commandInput) {
            choicesRoot.insertBefore(this.container, commandInput);
        } else if (!commandInput && this.container !== choicesRoot.lastElementChild) {
            choicesRoot.appendChild(this.container);
        }

        this.container.hidden = true;
        this.container.dataset.choiceReady = 'false';
    }

    handleChoices(choices) {
        this.choices = this.normalizeChoices(Array.isArray(choices) ? choices : []);
        this.render();
    }

    handleInputMode(inputMode) {
        this.inputMode = ['text', 'choice', 'end'].includes(inputMode) ? inputMode : 'text';
        this.render();
    }

    handleProcessState(state) {
        this.processState = state || 'ready';
        this.render();
    }

    handleKeyDown(event) {
        if (this.inputMode !== 'choice' || !this.choices.length) {
            return;
        }

        const optionsModal = document.getElementById('options-modal');
        if (optionsModal && optionsModal.style.display !== 'none') {
            return;
        }

        if (event.ctrlKey || event.metaKey || event.altKey || event.key.length !== 1) {
            return;
        }

        const letter = event.key.toUpperCase();
        const choice = this.choices.find((item) => item.letter === letter);
        if (!choice) {
            return;
        }

        event.preventDefault();
        this.selectChoice(choice.index);
    }

    normalizeChoices(choices) {
        return this.assignLetters(choices.slice(0, 26).map((choice, order) => {
            const tags = Array.isArray(choice.tags) ? choice.tags : [];
            const category = choice.category || this.getTagValue(tags, 'action');
            return {
                index: Number.isInteger(choice.index) ? choice.index : order,
                text: String(choice.text || ''),
                tags,
                category,
                letter: '',
                templateCell: this.getTemplateCell({ ...choice, tags, category })
            };
        }));
    }

    assignLetters(choices) {
        const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
        const reserved = new Set();

        choices.forEach((choice) => {
            const explicit = String(choice.letter || this.getTagValue(choice.tags, 'letter') || '')
                .trim()
                .charAt(0)
                .toUpperCase();
            const keyExplicit = String(choice.letter || this.getTagValue(choice.tags, 'key') || '')
                .trim()
                .charAt(0)
                .toUpperCase();
            const reservedLetter = explicit || keyExplicit;
            if (alphabet.includes(reservedLetter) && !reserved.has(reservedLetter)) {
                choice.letter = reservedLetter;
                reserved.add(reservedLetter);
            }
        });

        let nextLetterIndex = 0;
        choices.forEach((choice) => {
            if (choice.letter) return;
            while (nextLetterIndex < alphabet.length && reserved.has(alphabet[nextLetterIndex])) {
                nextLetterIndex += 1;
            }
            if (nextLetterIndex < alphabet.length) {
                choice.letter = alphabet[nextLetterIndex];
                reserved.add(choice.letter);
                nextLetterIndex += 1;
            }
        });

        return choices;
    }

    getTemplateCell(choice) {
        const entries = Object.entries(this.template.cells);
        const match = entries.find(([cellName, cell]) => {
            if (cellName === this.template.fallbackCell) return false;
            return typeof cell.match === 'function' && cell.match(choice);
        });
        return match ? match[0] : this.template.fallbackCell;
    }

    getTagValue(tags, key) {
        const normalizedKey = String(key).toLowerCase();
        const tag = tags.find((item) => String(item?.key || '').toLowerCase() === normalizedKey);
        return tag?.value;
    }

    render() {
        this.setupContainer();
        if (!this.container) return;

        this.container.innerHTML = '';
        const restoringHistory = document.documentElement.dataset.historyRestoring === 'true';
        const gameRunning = document.body?.dataset?.gameRunning === 'true';
        const readyForChoices = gameRunning &&
            !restoringHistory &&
            this.inputMode === 'choice' &&
            this.choices.length > 0 &&
            this.processState === 'ready';
        this.container.hidden = !readyForChoices;
        this.container.dataset.choiceReady = readyForChoices ? 'true' : 'false';
        if (this.container.hidden) {
            return;
        }

        const list = document.createElement('ol');
        list.className = 'choice-list choice-template-default';

        this.choices.forEach((choice) => {
            const item = document.createElement('li');
            item.className = 'choice-list-item';
            item.dataset.choiceIndex = String(choice.index);
            item.dataset.choiceLetter = choice.letter;
            item.dataset.templateCell = choice.templateCell;

            const button = document.createElement('button');
            button.type = 'button';
            button.className = 'choice-button';
            button.innerHTML = `<kbd>${this.escapeHtml(choice.letter)}</kbd><span>${this.renderChoiceText(choice.text)}</span>`;
            button.addEventListener('click', () => this.selectChoice(choice.index));
            item.appendChild(button);
            list.appendChild(item);
        });

        this.container.appendChild(list);
    }

    async selectChoice(index) {
        if (!this.socketClient) {
            this.socketClient = this.getModule('socket-client');
        }
        if (!this.socketClient || typeof this.socketClient.chooseChoice !== 'function') {
            console.error('ChoiceDisplay: Socket client cannot choose choices');
            return;
        }

        this.clear();
        document.dispatchEvent(new CustomEvent('story:process-state', {
            detail: { state: 'command-waiting', reason: 'choice-selected', choiceIndex: index }
        }));
        await this.socketClient.chooseChoice(index);
    }

    clear() {
        this.choices = [];
        if (this.container) {
            this.container.innerHTML = '';
            this.container.hidden = true;
        }
    }

    escapeHtml(text) {
        return String(text)
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;');
    }

    renderChoiceText(text) {
        if (!this.markupParser) {
            this.markupParser = this.getModule('markup-parser');
        }
        if (this.markupParser && typeof this.markupParser.markdownToHtml === 'function') {
            return this.markupParser.markdownToHtml(String(text || ''));
        }

        return this.escapeHtml(text)
            .replace(/\*\*\*([^*]+?)\*\*\*/g, '<strong><em>$1</em></strong>')
            .replace(/___([^_]+?)___/g, '<strong><em>$1</em></strong>')
            .replace(/\*\*([^*]+?)\*\*/g, '<strong>$1</strong>')
            .replace(/__([^_]+?)__/g, '<strong>$1</strong>')
            .replace(/\*([^*\s][^*]*?)\*/g, '<em>$1</em>')
            .replace(/_([^_\s][^_]*?)_/g, '<em>$1</em>');
    }
}

const choiceDisplay = new ChoiceDisplayModule();

export { choiceDisplay as ChoiceDisplay };

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

window.ChoiceDisplay = choiceDisplay;
