/**
 * @license
 * Copyright Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
import { getShadowElement } from '@tylertech/forge-core';
import { prefersReducedMotion } from '../core/utils/feature-detection';
import { VirtualElement } from '../core/utils/position-utils';
import { OVERLAY_CONSTANTS } from '../overlay';
import { OverlayAwareAdapter } from '../overlay/base/overlay-aware-adapter';
import { POPOVER_CONSTANTS } from './popover-constants';
export class PopoverAdapter extends OverlayAwareAdapter {
    constructor(component) {
        super(component);
        this._surfaceElement = getShadowElement(this._component, POPOVER_CONSTANTS.selectors.SURFACE);
    }
    destroy() {
        this._surfaceElement.classList.remove(POPOVER_CONSTANTS.classes.EXITING);
        this.cleanupAnchorElement();
    }
    _initializeOverlayElement() {
        this._overlayElement = getShadowElement(this._component, OVERLAY_CONSTANTS.elementName);
    }
    tryLocateAnchorElement(id) {
        this._overlayElement.anchorElement = this._tryFindAnchorElement(id);
        this._updateAnchorExpandedState(this._overlayElement.open);
    }
    initializeAnchorElement() {
        this._updateAnchorExpandedState(this._overlayElement.open);
    }
    cleanupAnchorElement() {
        this._updateAnchorExpandedState(null);
    }
    addAnchorListener(type, listener) {
        if (this._overlayElement.anchorElement instanceof VirtualElement) {
            return;
        }
        this._overlayElement.anchorElement?.addEventListener(type, listener);
    }
    removeAnchorListener(type, listener) {
        if (this._overlayElement.anchorElement instanceof VirtualElement) {
            return;
        }
        this._overlayElement.anchorElement?.removeEventListener(type, listener);
    }
    addSurfaceListener(type, listener) {
        this._surfaceElement.addEventListener(type, listener);
    }
    removeSurfaceListener(type, listener) {
        this._surfaceElement.removeEventListener(type, listener);
    }
    setOverlayOpen(newState) {
        this._surfaceElement.classList.remove(POPOVER_CONSTANTS.classes.EXITING);
        this._overlayElement.open = newState;
        this._updateAnchorExpandedState(newState);
    }
    hide() {
        if (prefersReducedMotion()) {
            this._surfaceElement.classList.remove(POPOVER_CONSTANTS.classes.EXITING);
            this._overlayElement.open = false;
            this._updateAnchorExpandedState(false);
            return Promise.resolve();
        }
        return new Promise(resolve => {
            this._surfaceElement.addEventListener('animationend', () => {
                this._surfaceElement.classList.remove(POPOVER_CONSTANTS.classes.EXITING);
                this._overlayElement.open = false;
                this._updateAnchorExpandedState(false);
                resolve();
            }, { once: true });
            this._surfaceElement.classList.add(POPOVER_CONSTANTS.classes.EXITING);
        });
    }
    toggleArrow(value) {
        if (value) {
            if (!this._arrowElement) {
                this._arrowElement = document.createElement('div');
                this._arrowElement.classList.add(POPOVER_CONSTANTS.classes.ARROW);
                this._arrowElement.setAttribute('part', POPOVER_CONSTANTS.parts.ARROW);
            }
            this._surfaceElement.appendChild(this._arrowElement);
            this._overlayElement.arrowElement = this._arrowElement;
        }
        else {
            this._arrowElement?.remove();
            this._arrowElement = undefined;
            this._overlayElement.arrowElement = undefined;
        }
    }
    isChildElement(element) {
        return this._component.contains(element);
    }
    tryAutofocus() {
        const tryFocus = () => {
            if (this._component.open && this._overlayElement.isConnected && !this._component.matches(':focus-within')) {
                const autofocusElement = this._component.querySelector('[autofocus]');
                if (autofocusElement) {
                    autofocusElement.focus();
                    return true;
                }
            }
            return false;
        };
        if (tryFocus()) {
            return;
        }
        window.requestAnimationFrame(() => {
            window.requestAnimationFrame(() => {
                tryFocus();
            });
        });
    }
    hasFocus() {
        return this._component.matches(':focus-within');
    }
    captureFocusedElement() {
        return this._component.ownerDocument.activeElement;
    }
    /**
     * Attempts to find the anchor element by first checking for an element with the provided id, and if not found,
     * then implicitly assumes the previous element sibling is the anchor.
     *
     * @param [id] - The id of the anchor element to locate.
     * @returns The anchor element if found, otherwise null.
     */
    _tryFindAnchorElement(id) {
        if (id) {
            // First we attempt to locate the target element based on the id reference provided
            const rootNode = this._component.getRootNode();
            const targetEl = rootNode.querySelector(`#${id}`);
            if (targetEl) {
                return targetEl;
            }
        }
        // If still not found, we'll implicitly assume the previous element sibling is our anchor
        if (this._component.previousElementSibling) {
            return this._component.previousElementSibling;
        }
        return null;
    }
    _updateAnchorExpandedState(state) {
        if (!this._overlayElement.anchorElement) {
            return;
        }
        if (!(this._overlayElement.anchorElement instanceof VirtualElement) && !this.overlayElement.anchorElement?.hasAttribute('aria-hidden')) {
            this._overlayElement.anchorElement.setAttribute('aria-expanded', String(!!state));
        }
    }
}
