/**
 * Panel Component - Reusable panel container for content sections
 * Extracted from DRS module patterns (explanation panels, hint panels, content sections)
 */

class Panel {
    constructor(options = {}) {
        // Default configuration
        this.config = {
            title: options.title || null,
            content: options.content || '',
            type: options.type || 'default', // default, info, success, warning, danger, hint, explanation
            collapsible: options.collapsible || false,
            collapsed: options.collapsed || false,
            closable: options.closable || false,
            onCollapse: options.onCollapse || null,
            onExpand: options.onExpand || null,
            onClose: options.onClose || null,
            className: options.className || '',
            id: options.id || null,
            ...options
        };

        this.element = null;
        this.headerElement = null;
        this.titleElement = null;
        this.bodyElement = null;
        this.toggleButton = null;
        this.closeButton = null;

        this._createPanel();
        Object.seal(this);
    }

    /**
     * Create the panel element
     * @private
     */
    _createPanel() {
        this.element = document.createElement('div');
        this.element.className = this._getPanelClasses();

        if (this.config.id) {
            this.element.id = this.config.id;
        }

        // Create panel structure
        this.element.innerHTML = this._getPanelHTML();

        // Get references to elements
        this.headerElement = this.element.querySelector('.panel-header');
        this.titleElement = this.element.querySelector('.panel-title');
        this.bodyElement = this.element.querySelector('.panel-body');
        this.toggleButton = this.element.querySelector('.panel-toggle');
        this.closeButton = this.element.querySelector('.panel-close');

        this._attachEventListeners();
        this._updateState();
        this._setupARIA();
    }

    /**
     * Get CSS classes for the panel
     * @returns {string} - Space-separated CSS classes
     * @private
     */
    _getPanelClasses() {
        const classes = ['panel'];

        // Type classes
        if (this.config.type !== 'default') {
            classes.push(`panel-${this.config.type}`);
        }

        // State classes
        if (this.config.collapsible) {
            classes.push('panel-collapsible');
        }

        if (this.config.collapsed) {
            classes.push('panel-collapsed');
        }

        // Custom classes
        if (this.config.className) {
            classes.push(this.config.className);
        }

        return classes.join(' ');
    }

    /**
     * Get panel HTML structure
     * @returns {string} - HTML string
     * @private
     */
    _getPanelHTML() {
        const hasHeader = this.config.title || this.config.collapsible || this.config.closable;

        return `
            ${hasHeader ? `
                <div class="panel-header">
                    ${this.config.title ? `<h4 class="panel-title">${this.config.title}</h4>` : ''}
                    <div class="panel-controls">
                        ${this.config.collapsible ? '<button class="panel-toggle" aria-label="Toggle panel">▼</button>' : ''}
                        ${this.config.closable ? '<button class="panel-close" aria-label="Close panel">✕</button>' : ''}
                    </div>
                </div>
            ` : ''}
            <div class="panel-body">
                ${this.config.content}
            </div>
        `;
    }

    /**
     * Attach event listeners
     * @private
     */
    _attachEventListeners() {
        if (this.toggleButton) {
            this.toggleButton.addEventListener('click', () => {
                this.toggle();
            });
        }

        if (this.closeButton) {
            this.closeButton.addEventListener('click', () => {
                this.close();
            });
        }

        // Allow clicking header to toggle if collapsible
        if (this.config.collapsible && this.headerElement) {
            this.headerElement.style.cursor = 'pointer';
            this.headerElement.addEventListener('click', (event) => {
                // Don't toggle if clicking on buttons
                if (!event.target.matches('.panel-toggle, .panel-close')) {
                    this.toggle();
                }
            });
        }
    }

    /**
     * Update panel state
     * @private
     */
    _updateState() {
        if (this.config.collapsed) {
            this.bodyElement.style.display = 'none';
            if (this.toggleButton) {
                this.toggleButton.textContent = '▶';
                this.toggleButton.setAttribute('aria-expanded', 'false');
            }
        } else {
            this.bodyElement.style.display = '';
            if (this.toggleButton) {
                this.toggleButton.textContent = '▼';
                this.toggleButton.setAttribute('aria-expanded', 'true');
            }
        }
    }

    /**
     * Setup ARIA attributes for accessibility
     * @private
     */
    _setupARIA() {
        if (this.config.collapsible) {
            this.element.setAttribute('aria-expanded', this.config.collapsed ? 'false' : 'true');

            if (this.bodyElement && this.toggleButton) {
                const bodyId = this.bodyElement.id || `panel-body-${Date.now()}`;
                this.bodyElement.id = bodyId;
                this.toggleButton.setAttribute('aria-controls', bodyId);
            }
        }
    }

    // Public API

    /**
     * Set panel title
     * @param {string} title - New title
     */
    setTitle(title) {
        this.config.title = title;

        if (title) {
            if (!this.titleElement) {
                // Create header structure if needed
                if (!this.headerElement) {
                    const headerHTML = `
                        <div class="panel-header">
                            <h4 class="panel-title">${title}</h4>
                            <div class="panel-controls">
                                ${this.config.collapsible ? '<button class="panel-toggle" aria-label="Toggle panel">▼</button>' : ''}
                                ${this.config.closable ? '<button class="panel-close" aria-label="Close panel">✕</button>' : ''}
                            </div>
                        </div>
                    `;
                    this.element.insertAdjacentHTML('afterbegin', headerHTML);
                    this.headerElement = this.element.querySelector('.panel-header');
                    this.titleElement = this.element.querySelector('.panel-title');
                    this.toggleButton = this.element.querySelector('.panel-toggle');
                    this.closeButton = this.element.querySelector('.panel-close');
                    this._attachEventListeners();
                } else {
                    // Just add title to existing header
                    const titleHTML = `<h4 class="panel-title">${title}</h4>`;
                    this.headerElement.insertAdjacentHTML('afterbegin', titleHTML);
                    this.titleElement = this.element.querySelector('.panel-title');
                }
            } else {
                this.titleElement.textContent = title;
            }
        } else if (this.titleElement) {
            this.titleElement.remove();
            this.titleElement = null;
        }

        return this;
    }

    /**
     * Set panel content
     * @param {string|HTMLElement} content - New content
     */
    setContent(content) {
        this.config.content = content;

        if (this.bodyElement) {
            if (typeof content === 'string') {
                this.bodyElement.innerHTML = content;
            } else if (content instanceof HTMLElement) {
                this.bodyElement.innerHTML = '';
                this.bodyElement.appendChild(content);
            }
        }

        return this;
    }

    /**
     * Append content to panel body
     * @param {string|HTMLElement} content - Content to append
     */
    appendContent(content) {
        if (this.bodyElement) {
            if (typeof content === 'string') {
                this.bodyElement.insertAdjacentHTML('beforeend', content);
            } else if (content instanceof HTMLElement) {
                this.bodyElement.appendChild(content);
            }
        }

        return this;
    }

    /**
     * Set panel type/theme
     * @param {string} type - Panel type (default, info, success, warning, danger, hint, explanation)
     */
    setType(type) {
        // Remove old type class
        this.element.className = this.element.className.replace(/panel-\w+/g, '');

        this.config.type = type;

        // Add new type class
        if (type !== 'default') {
            this.element.classList.add(`panel-${type}`);
        }

        return this;
    }

    /**
     * Expand the panel (if collapsible)
     * @param {boolean} animate - Whether to animate the expansion
     */
    expand(animate = true) {
        if (!this.config.collapsible || !this.config.collapsed) return this;

        this.config.collapsed = false;
        this.element.classList.remove('panel-collapsed');

        if (animate) {
            this.bodyElement.style.transition = 'max-height 0.3s ease, opacity 0.3s ease';
            this.bodyElement.style.maxHeight = '0';
            this.bodyElement.style.opacity = '0';
            this.bodyElement.style.display = '';

            requestAnimationFrame(() => {
                this.bodyElement.style.maxHeight = this.bodyElement.scrollHeight + 'px';
                this.bodyElement.style.opacity = '1';

                setTimeout(() => {
                    this.bodyElement.style.transition = '';
                    this.bodyElement.style.maxHeight = '';
                }, 300);
            });
        } else {
            this.bodyElement.style.display = '';
        }

        this._updateState();

        if (this.config.onExpand) {
            this.config.onExpand(this);
        }

        return this;
    }

    /**
     * Collapse the panel (if collapsible)
     * @param {boolean} animate - Whether to animate the collapse
     */
    collapse(animate = true) {
        if (!this.config.collapsible || this.config.collapsed) return this;

        this.config.collapsed = true;
        this.element.classList.add('panel-collapsed');

        if (animate) {
            this.bodyElement.style.transition = 'max-height 0.3s ease, opacity 0.3s ease';
            this.bodyElement.style.maxHeight = this.bodyElement.scrollHeight + 'px';
            this.bodyElement.style.opacity = '1';

            requestAnimationFrame(() => {
                this.bodyElement.style.maxHeight = '0';
                this.bodyElement.style.opacity = '0';

                setTimeout(() => {
                    this.bodyElement.style.display = 'none';
                    this.bodyElement.style.transition = '';
                    this.bodyElement.style.maxHeight = '';
                    this.bodyElement.style.opacity = '';
                }, 300);
            });
        } else {
            this.bodyElement.style.display = 'none';
        }

        this._updateState();

        if (this.config.onCollapse) {
            this.config.onCollapse(this);
        }

        return this;
    }

    /**
     * Toggle panel collapsed state
     * @param {boolean} animate - Whether to animate the toggle
     */
    toggle(animate = true) {
        if (this.config.collapsed) {
            this.expand(animate);
        } else {
            this.collapse(animate);
        }

        return this;
    }

    /**
     * Close/remove the panel
     * @param {boolean} animate - Whether to animate the close
     */
    close(animate = true) {
        if (this.config.onClose) {
            // Allow onClose to prevent closing by returning false
            if (this.config.onClose(this) === false) {
                return this;
            }
        }

        if (animate) {
            this.element.style.transition = 'opacity 0.3s ease, transform 0.3s ease';
            this.element.style.opacity = '0';
            this.element.style.transform = 'translateY(-10px)';

            setTimeout(() => {
                this.remove();
            }, 300);
        } else {
            this.remove();
        }

        return this;
    }

    /**
     * Enable or disable collapsible functionality
     * @param {boolean} collapsible - Whether panel can be collapsed
     */
    setCollapsible(collapsible) {
        this.config.collapsible = collapsible;
        this.element.classList.toggle('panel-collapsible', collapsible);

        if (collapsible && !this.toggleButton) {
            // Add toggle button
            if (!this.headerElement) {
                // Create header first
                const headerHTML = `
                    <div class="panel-header">
                        ${this.config.title ? `<h4 class="panel-title">${this.config.title}</h4>` : ''}
                        <div class="panel-controls">
                            <button class="panel-toggle" aria-label="Toggle panel">▼</button>
                        </div>
                    </div>
                `;
                this.element.insertAdjacentHTML('afterbegin', headerHTML);
                this.headerElement = this.element.querySelector('.panel-header');
            } else {
                // Add to existing controls
                let controlsDiv = this.headerElement.querySelector('.panel-controls');
                if (!controlsDiv) {
                    controlsDiv = document.createElement('div');
                    controlsDiv.className = 'panel-controls';
                    this.headerElement.appendChild(controlsDiv);
                }
                controlsDiv.insertAdjacentHTML('afterbegin', '<button class="panel-toggle" aria-label="Toggle panel">▼</button>');
            }

            this.toggleButton = this.element.querySelector('.panel-toggle');
            this._attachEventListeners();
            this._setupARIA();
        } else if (!collapsible && this.toggleButton) {
            this.toggleButton.remove();
            this.toggleButton = null;
        }

        return this;
    }

    /**
     * Show the panel
     */
    show() {
        this.element.style.display = '';
        return this;
    }

    /**
     * Hide the panel
     */
    hide() {
        this.element.style.display = 'none';
        return this;
    }

    /**
     * Add CSS class to panel
     * @param {string} className - CSS class to add
     */
    addClass(className) {
        this.element.classList.add(className);
        return this;
    }

    /**
     * Remove CSS class from panel
     * @param {string} className - CSS class to remove
     */
    removeClass(className) {
        this.element.classList.remove(className);
        return this;
    }

    /**
     * Get the DOM element
     * @returns {HTMLElement} - The panel element
     */
    getElement() {
        return this.element;
    }

    /**
     * Get panel header element
     * @returns {HTMLElement|null} - The header element
     */
    getHeader() {
        return this.headerElement;
    }

    /**
     * Get panel body element
     * @returns {HTMLElement} - The body element
     */
    getBody() {
        return this.bodyElement;
    }

    /**
     * Append panel to a container
     * @param {HTMLElement} container - Container to append to
     */
    appendTo(container) {
        if (container && container.appendChild) {
            container.appendChild(this.element);
        }
        return this;
    }

    /**
     * Remove panel from DOM
     */
    remove() {
        if (this.element && this.element.parentNode) {
            this.element.parentNode.removeChild(this.element);
        }
        return this;
    }

    /**
     * Destroy the panel and clean up
     */
    destroy() {
        this.remove();
        this.element = null;
        this.headerElement = null;
        this.titleElement = null;
        this.bodyElement = null;
        this.toggleButton = null;
        this.closeButton = null;
        this.config = null;
    }

    // Static factory methods

    /**
     * Create an info panel
     * @param {string} title - Panel title
     * @param {string} content - Panel content
     * @param {Object} options - Additional options
     * @returns {Panel} - Panel instance
     */
    static info(title, content, options = {}) {
        return new Panel({
            title,
            content,
            type: 'info',
            ...options
        });
    }

    /**
     * Create a hint panel (collapsible by default)
     * @param {string} content - Hint content
     * @param {Object} options - Additional options
     * @returns {Panel} - Panel instance
     */
    static hint(content, options = {}) {
        return new Panel({
            title: 'Hint',
            content,
            type: 'hint',
            collapsible: true,
            collapsed: true,
            ...options
        });
    }

    /**
     * Create an explanation panel
     * @param {string} title - Explanation title
     * @param {string} content - Explanation content
     * @param {Object} options - Additional options
     * @returns {Panel} - Panel instance
     */
    static explanation(title, content, options = {}) {
        return new Panel({
            title,
            content,
            type: 'explanation',
            ...options
        });
    }

    /**
     * Create a warning panel
     * @param {string} message - Warning message
     * @param {Object} options - Additional options
     * @returns {Panel} - Panel instance
     */
    static warning(message, options = {}) {
        return new Panel({
            content: message,
            type: 'warning',
            ...options
        });
    }

    /**
     * Create a success panel
     * @param {string} message - Success message
     * @param {Object} options - Additional options
     * @returns {Panel} - Panel instance
     */
    static success(message, options = {}) {
        return new Panel({
            content: message,
            type: 'success',
            ...options
        });
    }
}

export default Panel;