/**
 * ProgressBar Component - Reusable progress indicator
 * Extracted from DRS module patterns (question progress, loading, etc.)
 */

class ProgressBar {
    constructor(options = {}) {
        // Default configuration
        this.config = {
            value: options.value || 0, // 0-100
            max: options.max || 100,
            min: options.min || 0,
            animated: options.animated !== false, // true by default
            striped: options.striped || false,
            showLabel: options.showLabel !== false, // true by default
            label: options.label || null, // custom label, defaults to percentage
            size: options.size || 'normal', // sm, normal, lg
            color: options.color || 'primary', // primary, success, warning, danger, info
            className: options.className || '',
            id: options.id || null,
            ...options
        };

        this.element = null;
        this.progressFill = null;
        this.progressLabel = null;

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

    /**
     * Create the progress bar element
     * @private
     */
    _createProgressBar() {
        this.element = document.createElement('div');
        this.element.className = this._getProgressClasses();

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

        // Create progress structure
        this.element.innerHTML = this._getProgressHTML();

        // Get references to inner elements
        this.progressFill = this.element.querySelector('.progress-fill');
        this.progressLabel = this.element.querySelector('.progress-label');

        this._updateProgress();
        this._setupARIA();
    }

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

        // Size classes
        if (this.config.size !== 'normal') {
            classes.push(`progress-bar-${this.config.size}`);
        }

        // Animation classes
        if (this.config.animated) {
            classes.push('progress-bar-animated');
        }

        if (this.config.striped) {
            classes.push('progress-bar-striped');
        }

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

        return classes.join(' ');
    }

    /**
     * Get progress bar HTML structure
     * @returns {string} - HTML string
     * @private
     */
    _getProgressHTML() {
        return `
            <div class="progress-track">
                <div class="progress-fill progress-fill-${this.config.color}"></div>
            </div>
            ${this.config.showLabel ? '<div class="progress-label"></div>' : ''}
        `;
    }

    /**
     * Update progress value and display
     * @private
     */
    _updateProgress() {
        const percentage = this._calculatePercentage();

        // Update fill width
        if (this.progressFill) {
            this.progressFill.style.width = `${percentage}%`;
        }

        // Update label
        if (this.progressLabel && this.config.showLabel) {
            this.progressLabel.textContent = this._getDisplayLabel();
        }

        // Update ARIA
        this._updateARIA();
    }

    /**
     * Calculate percentage value
     * @returns {number} - Percentage (0-100)
     * @private
     */
    _calculatePercentage() {
        const { value, min, max } = this.config;
        const clampedValue = Math.max(min, Math.min(max, value));
        return ((clampedValue - min) / (max - min)) * 100;
    }

    /**
     * Get display label text
     * @returns {string} - Label text
     * @private
     */
    _getDisplayLabel() {
        if (this.config.label !== null) {
            return this.config.label;
        }

        return `${Math.round(this._calculatePercentage())}%`;
    }

    /**
     * Setup ARIA attributes for accessibility
     * @private
     */
    _setupARIA() {
        this.element.setAttribute('role', 'progressbar');
        this._updateARIA();
    }

    /**
     * Update ARIA attributes
     * @private
     */
    _updateARIA() {
        this.element.setAttribute('aria-valuenow', this.config.value);
        this.element.setAttribute('aria-valuemin', this.config.min);
        this.element.setAttribute('aria-valuemax', this.config.max);

        if (this.config.label) {
            this.element.setAttribute('aria-label', this.config.label);
        } else {
            this.element.setAttribute('aria-label', `${Math.round(this._calculatePercentage())}% complete`);
        }
    }

    // Public API

    /**
     * Set progress value
     * @param {number} value - New progress value
     * @param {boolean} animate - Whether to animate the change
     */
    setValue(value, animate = true) {
        this.config.value = value;

        if (animate && this.config.animated) {
            this._animateProgress();
        } else {
            this._updateProgress();
        }
        return this;
    }

    /**
     * Get current progress value
     * @returns {number} - Current value
     */
    getValue() {
        return this.config.value;
    }

    /**
     * Set progress to a percentage
     * @param {number} percentage - Percentage (0-100)
     * @param {boolean} animate - Whether to animate
     */
    setPercentage(percentage, animate = true) {
        const value = this.config.min + ((percentage / 100) * (this.config.max - this.config.min));
        return this.setValue(value, animate);
    }

    /**
     * Get current percentage
     * @returns {number} - Percentage (0-100)
     */
    getPercentage() {
        return this._calculatePercentage();
    }

    /**
     * Set custom label
     * @param {string|null} label - Label text or null for percentage
     */
    setLabel(label) {
        this.config.label = label;
        this._updateProgress();
        return this;
    }

    /**
     * Show or hide the label
     * @param {boolean} show - Whether to show label
     */
    showLabel(show = true) {
        this.config.showLabel = show;

        if (show && !this.progressLabel) {
            // Add label if it doesn't exist
            const labelElement = document.createElement('div');
            labelElement.className = 'progress-label';
            this.element.appendChild(labelElement);
            this.progressLabel = labelElement;
        } else if (!show && this.progressLabel) {
            // Hide label
            this.progressLabel.style.display = 'none';
        } else if (show && this.progressLabel) {
            // Show existing label
            this.progressLabel.style.display = '';
        }

        this._updateProgress();
        return this;
    }

    /**
     * Set progress bar color
     * @param {string} color - Color theme (primary, success, warning, danger, info)
     */
    setColor(color) {
        if (this.progressFill) {
            // Remove old color class
            this.progressFill.className = this.progressFill.className
                .replace(/progress-fill-\w+/g, '');

            // Add new color class
            this.progressFill.classList.add(`progress-fill-${color}`);
        }
        this.config.color = color;
        return this;
    }

    /**
     * Enable or disable animation
     * @param {boolean} animated - Whether to animate
     */
    setAnimated(animated) {
        this.config.animated = animated;
        this.element.classList.toggle('progress-bar-animated', animated);
        return this;
    }

    /**
     * Enable or disable striped pattern
     * @param {boolean} striped - Whether to show stripes
     */
    setStriped(striped) {
        this.config.striped = striped;
        this.element.classList.toggle('progress-bar-striped', striped);
        return this;
    }

    /**
     * Animate progress change smoothly
     * @private
     */
    _animateProgress() {
        if (!this.progressFill) return;

        const targetPercentage = this._calculatePercentage();
        const currentWidth = parseFloat(this.progressFill.style.width) || 0;

        // Use CSS transition for smooth animation
        this.progressFill.style.transition = 'width 0.5s ease';
        this.progressFill.style.width = `${targetPercentage}%`;

        // Update label after animation
        setTimeout(() => {
            if (this.progressLabel && this.config.showLabel) {
                this.progressLabel.textContent = this._getDisplayLabel();
            }
            this._updateARIA();
        }, 500);
    }

    /**
     * Increment progress by a certain amount
     * @param {number} amount - Amount to increment
     * @param {boolean} animate - Whether to animate
     */
    increment(amount = 1, animate = true) {
        return this.setValue(this.config.value + amount, animate);
    }

    /**
     * Decrement progress by a certain amount
     * @param {number} amount - Amount to decrement
     * @param {boolean} animate - Whether to animate
     */
    decrement(amount = 1, animate = true) {
        return this.setValue(this.config.value - amount, animate);
    }

    /**
     * Reset progress to minimum value
     * @param {boolean} animate - Whether to animate
     */
    reset(animate = true) {
        return this.setValue(this.config.min, animate);
    }

    /**
     * Set progress to maximum value
     * @param {boolean} animate - Whether to animate
     */
    complete(animate = true) {
        return this.setValue(this.config.max, animate);
    }

    /**
     * Check if progress is complete
     * @returns {boolean} - Whether progress is at maximum
     */
    isComplete() {
        return this.config.value >= this.config.max;
    }

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

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

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

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

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

    /**
     * Destroy the progress bar and clean up
     */
    destroy() {
        this.remove();
        this.element = null;
        this.progressFill = null;
        this.progressLabel = null;
        this.config = null;
    }

    // Static factory methods

    /**
     * Create a primary progress bar
     * @param {number} value - Initial value
     * @param {Object} options - Additional options
     * @returns {ProgressBar} - ProgressBar instance
     */
    static primary(value = 0, options = {}) {
        return new ProgressBar({
            value,
            color: 'primary',
            ...options
        });
    }

    /**
     * Create a success progress bar
     * @param {number} value - Initial value
     * @param {Object} options - Additional options
     * @returns {ProgressBar} - ProgressBar instance
     */
    static success(value = 0, options = {}) {
        return new ProgressBar({
            value,
            color: 'success',
            ...options
        });
    }

    /**
     * Create a warning progress bar
     * @param {number} value - Initial value
     * @param {Object} options - Additional options
     * @returns {ProgressBar} - ProgressBar instance
     */
    static warning(value = 0, options = {}) {
        return new ProgressBar({
            value,
            color: 'warning',
            ...options
        });
    }

    /**
     * Create a loading progress bar with indeterminate animation
     * @param {Object} options - Additional options
     * @returns {ProgressBar} - ProgressBar instance
     */
    static loading(options = {}) {
        return new ProgressBar({
            value: 50,
            animated: true,
            striped: true,
            showLabel: false,
            className: 'progress-bar-indeterminate',
            ...options
        });
    }
}

export default ProgressBar;