import { Build } from "@stencil/core";
import { Effect, Queue, Stream } from "effect";
export class AriaValidationController {
    host;
    config;
    static get globalValidationEnabled() {
        return Build.isDev;
    }
    static axe = this.globalValidationEnabled ? import('axe-core') : null;
    static axeQueue = null;
    static axeStreamFiber = null;
    visibilityObserver;
    elementQueued = false;
    elementValidated = false;
    knownValidationErrors = [];
    get disabled() {
        return !AriaValidationController.globalValidationEnabled;
    }
    constructor(host, config) {
        this.host = host;
        this.config = config;
        AriaValidationController.initializeAxeStream();
    }
    static initializeAxeStream() {
        if (!this.globalValidationEnabled)
            return;
        if (this.axeStreamFiber)
            return;
        const program = Effect.gen(function* () {
            const queue = (AriaValidationController.axeQueue = yield* Queue.bounded(100));
            const axeLib = yield* Effect.promise(() => AriaValidationController.axe);
            if (!axeLib) {
                console.error('Axe library not available, ARIA validation will not run.');
                return;
            }
            const stream = Stream.fromQueue(queue).pipe(Stream.mapEffect(({ context, onComplete }) => Effect.async(resume => {
                axeLib.run(context, {}, (error, results) => {
                    onComplete(error, results);
                    resume(Effect.void);
                });
            })));
            yield* Stream.runDrain(stream);
        });
        this.axeStreamFiber = Effect.runFork(program);
    }
    hostDidLoad() {
        if (this.elementQueued || this.elementValidated)
            return;
        if (!this.host.el.checkVisibility()) {
            this.observeVisibilityOnce();
            return;
        }
        this.enqueueValidation();
    }
    hostDidUpdate() {
        this.checkLazyValidation();
    }
    hostDisconnected() {
        this.discardVisibilityObserver();
    }
    observeVisibilityOnce() {
        this.visibilityObserver = new IntersectionObserver(entries => {
            for (const entry of entries) {
                if (entry.target !== this.host.el)
                    continue;
                if (!entry.isIntersecting)
                    continue;
                this.checkLazyValidation();
                this.discardVisibilityObserver();
            }
        }, {
            root: this.host.el.parentElement,
            rootMargin: '0px',
            threshold: 0.01,
        });
        this.visibilityObserver.observe(this.host.el);
    }
    checkLazyValidation() {
        if (!this.config?.reValidateOnPropChanges && (this.elementQueued || this.elementValidated))
            return;
        this.enqueueValidation();
    }
    enqueueValidation() {
        if (!AriaValidationController.globalValidationEnabled)
            return;
        this.elementQueued = true;
        Effect.runPromise(AriaValidationController.axeQueue?.offer({
            context: { include: this.host.el, exclude: this.knownValidationErrors },
            onComplete: (error, results) => {
                this.elementValidated = true;
                if (error) {
                    console.error('Error running ARIA validation:', error);
                    return;
                }
                if (!results?.violations.length) {
                    if (this.config?.verboseLogging) {
                        console.log(`No ARIA validation violations found for ${this.host.el?.tagName || 'element'}.`);
                    }
                    return;
                }
                const label = `ARIA validation violations found for ${this.host.el?.tagName || 'element'}`;
                if (this.config?.verboseLogging) {
                    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);
                });
                console.log('element:', this.host.el);
                console.groupEnd();
                this.knownValidationErrors.push(...targets);
            },
        }));
    }
    discardVisibilityObserver() {
        if (!this.visibilityObserver)
            return;
        this.visibilityObserver.disconnect();
        this.visibilityObserver = undefined;
    }
}
