class StagedProgress extends HTMLElement {
    static get observedAttributes() { return ["aria-value"]; };

    get value() {
        return this.getAttribute('aria-value') || this._value;
    };

    set value(value) {
        this._value = value;
        this.setAttribute('aria-value', value);
    };

    set min(value) {
        this._min = value;
    };

    set max(value) {
        this._max = value;
    }

    constructor() {
        super();
        this._isIntialized;
        this._value;
        this._min = 0;
        this._max = 100;
    }

    dispose() {
        this._value = null;
        this._isIntialized = null;
        this._min = null;
        this._max = null;
    }

    connectedCallback() {
        const instance = document.importNode(window.templates.get("staged-progress"), true);

        this.appendChild(instance);
        this._isIntialized = true;

        if (this.value)
            this.setProgress(this.value);

        this.setDefaultAttributes();
    }

    disconnectedCallback() {
        this.dispose();
    }

    attributeChangedCallback(name, oldValue, newValue) {

        if (this._isIntialized === true)
            this.setProgress(newValue);
    }

    setDefaultAttributes() {
        if (!this.hasAttribute('role'))
            this.setAttribute('role', 'progressbar');

        if (!this.hasAttribute('aria-valuemin'))
            this.setAttribute('aria-valuemin', this._min);

        if (!this.hasAttribute('aria-valuemax'))
            this.setAttribute('aria-valuemax', this._max);
    }

    setProgress(value) {

        if (this.validProgress(value)) {
            const progress = this.querySelector('.progress');
            const span = progress.querySelector('span');

            this.setAttribute('aria-valuenow', value);
            progress.setAttribute('data-progress', value);
            span.style.width = value + "%";

            this.dispatchEvent(new CustomEvent('onProgressChanged', {
                detail: {
                    progress: value
                },
            }));
        }
    }

    getProgressType() {
        return isNaN(this.value) ? "enum" : "numeric";
    }

    validProgress(value) {
        const progress = Number(value);

        if (this.getProgressType() === "numeric")
            return progress >= this._min && progress <= this._max;

        return true;
    }
}

customElements.define('staged-progress', StagedProgress);

class StageIndicator extends HTMLElement {
    static get observedAttributes() {
        return ["aria-value", "title"];
    };

    get value() {
        return this.getAttribute("aria-value") || this._value;
    };

    set value(value) {
        this._value = value;
        this.setAttribute('aria-value', value);
    };

    get title() {
        return this.getAttribute('title') || this._title;
    }

    set title(value) {
        this._title = value;
        this.setAttribute('title', value);
    }

    constructor() {
        super();
        this._value;
        this._title;
        this._isInitialized;
        this.onProgressHandle;
    }

    dispose() {
        this.removeEventListener('click', this.onStageClicked);
        this.removeEventListener('onProgressChanged', this.onProgressHandle);

        this.onProgressHandle = null;
        this._value = null;
        this._title = null;
        this._isInitialized = null;
    }

    connectedCallback() {
        this._isInitialized = true;

        if (this.value) {
            this.setStagePosition(this.value);
            this.setCompletedState(this.parentElement.value)
        };

        this.onProgressHandle = this.onProgress.bind(this);

        this.addEventListener("click", this.onStageClicked);
        this.parentElement.addEventListener("onProgressChanged", this.onProgressHandle);
    }

    disconnectedCallback() {
        this.dispose();
    }

    attributeChangedCallback(name, oldValue, newValue) {
        if (!this._isInitialized)
            return;

        this.setStagePosition(newValue);
        this.setCompletedState(this.parentElement.value);
    }

    setStagePosition(value) {
        const size = this.offsetWidth;
        const position = this.convertToNumber(value);

        if (position > 0)
            this.style.left = `calc(${value}% - ${size}px)`;
        else
            this.style.left = value;

    }

    setCompletedState(progress) {
        const progressType = this.parentElement.getProgressType();

        switch (progressType) {
            case "numeric":
                this.setNumericProgressState(progress);
                break;
            case "enum":
                this.setEnumProgressState(progress);
                break;
            default:
                console.log("unsupported progress type");
        }
    }

    setNumericProgressState(progress) {
        const value = this.convertToNumber(this.value);
        const numericProgress = this.convertToNumber(progress);

        numericProgress >= value
            ? this.classList.add('completed')
            : this.classList.remove('completed');
    }

    setEnumProgressState() {
        if (this.parentElement.value === this.title) {

            this.parentElement.value = this.value;
            this.classList.add('completed');
        }
        else
            this.classList.remove('completed');
    }

    onStageClicked(e) {
        const position = this.value;

        this.parentElement.value = position;
        this.classList.add('completed');
    };

    onProgress(event) {
        const progress = this.convertToNumber(event.detail.progress);

        this.setCompletedState(progress);
    }

    convertToNumber(value) {
        return Number(value);
    }
}

customElements.define('staged-indicator', StageIndicator);
