import { ARIA_VALIDATION_RUNTIME_CHANGED_EVENT, enableAriaValidation, isAriaValidationEnabled, queueValidation, useVerboseLogging, } from "@lmvz-ds/aria-validation";
import { Build } from "@stencil/core";
if (Build.isDev && Build.isBrowser) {
    enableAriaValidation();
}
export class AriaValidationController {
    host;
    config;
    visibilityObserver;
    elementQueued = false;
    elementValidated = false;
    elementLoaded = false;
    static knownValidationErrors = [];
    get disabled() {
        return !isAriaValidationEnabled();
    }
    get useVerboseLogging() {
        return this.config?.verboseLogging || Build.isDev || useVerboseLogging();
    }
    constructor(host, config) {
        this.host = host;
        this.config = config;
    }
    onRuntimeConfigChange = () => {
        if (!isAriaValidationEnabled())
            return;
        this.checkLazyValidation();
    };
    hostDidLoad() {
        this.elementLoaded = true;
        if (typeof window !== 'undefined') {
            window.addEventListener(ARIA_VALIDATION_RUNTIME_CHANGED_EVENT, this.onRuntimeConfigChange);
        }
        if (this.elementQueued || this.elementValidated)
            return;
        if (this.config?.validationTiming === 'slot') {
            this.observeSlot();
            return;
        }
        if (!this.host.validationEl?.checkVisibility?.() || this.config?.validationTiming !== 'load') {
            this.observeVisibilityOnce();
            return;
        }
        this.enqueueValidation();
    }
    hostDidUpdate() {
        this.checkLazyValidation();
    }
    hostDisconnected() {
        this.discardVisibilityObserver();
        if (typeof window !== 'undefined') {
            window.removeEventListener(ARIA_VALIDATION_RUNTIME_CHANGED_EVENT, this.onRuntimeConfigChange);
        }
    }
    revalidateAria() {
        this.enqueueValidation();
    }
    observeSlot() {
        this.host.validationSlot?.addEventListener('slotchange', this.enqueueValidation.bind(this));
    }
    observeVisibilityOnce() {
        if (Build.isBrowser) {
            window.setTimeout(() => {
                if (!this.host.validationEl)
                    return;
                this.visibilityObserver = new IntersectionObserver((entries) => {
                    for (const entry of entries) {
                        if (entry.target !== this.host.validationEl)
                            continue;
                        if (!entry.isIntersecting)
                            continue;
                        this.checkLazyValidation();
                        this.discardVisibilityObserver();
                    }
                }, {
                    root: this.host.validationEl?.parentElement,
                    rootMargin: '0px',
                    threshold: 0.01,
                });
                this.visibilityObserver.observe(this.host.validationEl);
            });
        }
    }
    checkLazyValidation() {
        if (!this.elementLoaded)
            return;
        if (!this.config?.reValidateOnPropChanges && (this.elementQueued || this.elementValidated))
            return;
        if (!this.host.validationEl?.checkVisibility?.())
            return;
        this.enqueueValidation();
    }
    enqueueValidation() {
        if (!isAriaValidationEnabled())
            return;
        this.elementQueued = true;
        queueValidation({
            context: { include: this.host.validationEl, exclude: AriaValidationController.knownValidationErrors },
            onComplete: (error, results) => {
                this.elementValidated = true;
                const elementName = this.host.tagName || this.host.validationEl?.tagName || 'Element';
                if (error) {
                    console.error('Error running ARIA validation:', error, elementName);
                    if (!this.host.validationEl?.tagName) {
                        console.dir(this.host);
                    }
                    return;
                }
                const message = [elementName];
                if (!results?.violations.length) {
                    if (this.useVerboseLogging) {
                        console.log(...message, 'has no ARIA violations');
                        if (!this.host.validationEl?.tagName) {
                            console.dir(this.host);
                        }
                    }
                    return;
                }
                const count = results.violations.length;
                const label = [...message, results.violations.at(0).id, count > 1 ? `(+${count - 1} more)` : ''].filter(Boolean).join(' ');
                if (this.useVerboseLogging) {
                    console.group(label);
                }
                else {
                    console.groupCollapsed(label);
                }
                const targets = results.violations.flatMap((violation) => {
                    console.dir(violation, { showHidden: true, compact: false });
                    return violation.nodes.map((node) => node.target);
                });
                if (this.host.validationEl) {
                    console.log('element:', this.host.validationEl);
                }
                else {
                    console.dir(this.host);
                }
                console.groupEnd();
                AriaValidationController.knownValidationErrors.push(...targets);
            },
        });
    }
    discardVisibilityObserver() {
        if (Build.isBrowser) {
            if (!this.visibilityObserver)
                return;
            this.visibilityObserver.disconnect();
            this.visibilityObserver = undefined;
        }
    }
}
