/// Builds an alert message that appears at the bottom of the page.

const PAGE_ALERT_DEFAULT_TIMEOUT = 5000; // ms
const PAGE_ALERT_FAST_TIMEOUT = 250;
const PAGE_ALERT_DIALOG_CLSS = "pageAlert";
const PAGE_ALERT_DIALOG_HIDDEN_CLSS = "hidden";

class PageAlertBuilder {
    constructor() {
        this.text_ = "";
        this.timeout_ = PAGE_ALERT_DEFAULT_TIMEOUT;
    }

    /// Sets the alert's text to [text]
    withText(text) {
        this.text_ = text;

        return this;
    }

    /// Destroys the alert after [timeout] ms instead of the
    /// default.
    withTimeout(timeout) {
        this.timeout_ = timeout;

        return this;
    }

    /// Keep the dialog open after its initial appearance.
    withoutTimeout() {
        this.timeout_ = -1;

        return this;
    }

    /// Don't show the announcement to the user. Useful for accessibility-
    ///related announcements.
    invisible() {
        this.invisible_ = true;

        return this;
    }

    /// Build, but don't yet show the alert. Returns an object
    /// with [show] and [destroy] methods.
    build() {
        let destroyTimeout = -1;
        let dialog = document.createElement("div");
        let messageArea = document.createElement("div");

        dialog.classList.add(PAGE_ALERT_DIALOG_CLSS);
        dialog.setAttribute('role', 'alert');

        messageArea.innerText = this.text_;
        dialog.appendChild(messageArea);

        if (this.invisible_) {
            dialog.classList.add(PAGE_ALERT_DIALOG_HIDDEN_CLSS);
            dialog.style.opacity = 0;
            dialog.style.pointerEvents = 'none';
            console.log("PageAlert-invisible", this.text_);
        }

        /// Removes the dialog.
        let destroying = false;
        let destroy = () => {
            if (destroying) {
                return;
            }

            // Fade out.
            dialog.classList.add("closing");
            destroying = true;

            requestAnimationFrame(() => {
                let animDurationStr = getComputedStyle(dialog).getPropertyValue("animation-duration");
                let destroyAnimationDuration;

                // Get the duration in milliseconds.
                let secMatches = /^(\d+\.?\d*)s$/.exec(animDurationStr);
                let millisMatches = /^(\d+)ms$/.exec(animDurationStr);

                if (secMatches) {
                    destroyAnimationDuration = parseFloat(secMatches[1]) * 1000;
                }
                else if (millisMatches) {
                    destroyAnimationDuration = parseInt(millisMatches[1]);
                }

                // If we weren't able to get a reasonable value
                if (isNaN(destroyAnimationDuration)) {
                    console.warn(
                        `${animDurationStr} doesn't seem to be a value in milliseconds or seconds. ` +
                        `Exit animations for alerts may be disabled`
                    );
                    destroyAnimationDuration = 0;
                }

                setTimeout(() => {
                    dialog.remove();
                    dialog = null;
                    destroying = false;

                    if (destroyTimeout !== -1) {
                        clearTimeout(destroyTimeout);
                        destroyTimeout = -1;
                    }
                }, destroyAnimationDuration);
            });
        };

        return {
            show: () => {
                document.body.appendChild(dialog);

                if (this.timeout_ != -1) {
                    destroyTimeout = setTimeout(() => {
                        destroy();
                    }, this.timeout_);
                }
            },
            destroy,
        };
    }
}

var PageAlert = {
    builder() {
        return new PageAlertBuilder();
    }
};

/// Short method for creating an invisible alert with [text].
function announceForAccessibility(text) {
    return PageAlert.builder()
                    .withText(text)
                    .invisible()
                    .withTimeout(PAGE_ALERT_FAST_TIMEOUT)
                    .build().show();
}

export { PageAlert, announceForAccessibility };
export default PageAlert;