/* eslint-disable no-restricted-syntax */
// #region Imports
import { on } from '@breadstone/mosaik-elements';
import { RendererServiceLocator } from '../../../../Dom/Renderer';
import { ScrollerServiceLocator } from '../../../../Dom/Scroller';
import { ControllerBase } from '../../../Controllers/Abstracts/ControllerBase';
/**
 * A controller that enables sticky positioning via flexible strategies.
 *
 * @public
 */
export class StickyController extends ControllerBase {
    // #region Fields
    _strategy;
    _options;
    // #endregion
    // #region Ctor
    /**
     * Constructs a new instance of the `StickyController` class.
     *
     * @param host - The controller host element.
     * @param options - Optional configuration for the sticky controller.
     *
     * @public
     */
    constructor(host, options) {
        super(host);
        this._options = options ?? {
            top: '0px',
            left: '0px'
        };
    }
    // #endregion
    // #region Properties
    /**
     * Gets or sets the `top` property.
     *
     * @public
     * @writeonly
     */
    set top(value) {
        if (this._options.top !== value) {
            this._options.top = value;
            this.applyCssVariables();
        }
    }
    /**
     * Gets or sets the `left` property.
     *
     * @public
     * @writeonly
     */
    set left(value) {
        if (this._options.left !== value) {
            this._options.left = value;
            this.applyCssVariables();
        }
    }
    // #endregion
    // #region Methods
    /**
     * @public
     */
    hostConnected() {
        super.hostConnected();
        this.applyCssVariables();
        this._strategy = this.hasScrollableParent(this.host)
            ? new ParentBoundStickyStrategy(this.host)
            : new ScrollPositionStickyStrategy(this.host);
        this._strategy.attach();
    }
    /**
     * @public
     */
    hostDisconnected() {
        this._strategy?.detach();
        super.hostDisconnected();
    }
    /**
     * @private
     */
    applyCssVariables() {
        RendererServiceLocator.current.setStyle(this.host, '--sticky-top', this._options.top ?? '0px');
        RendererServiceLocator.current.setStyle(this.host, '--sticky-left', this._options.left ?? '0px');
    }
    /**
     * @private
     */
    hasScrollableParent(el) {
        while (el && el !== document.body) {
            const style = window.getComputedStyle(el);
            const overflowY = style.overflowY;
            if ((/(auto|scroll|overlay)/).test(overflowY))
                return true;
            el = el.parentElement;
        }
        return false;
    }
}
/**
 * Uses native `position: sticky` CSS logic.
 * Works only if the host has a scrollable ancestor.
 *
 * @private
 */
class ParentBoundStickyStrategy {
    // #region Fields
    _element;
    // #endregion
    // #region Ctor
    constructor(element) {
        this._element = element;
    }
    // #endregion
    // #region Methods
    /**
     * @public
     */
    attach() {
        RendererServiceLocator.current.setStyle(this._element, 'position', 'sticky');
        RendererServiceLocator.current.setStyle(this._element, '--sticky-top', this._element.style.getPropertyValue('--sticky-top') || '0px');
        RendererServiceLocator.current.setStyle(this._element, '--sticky-left', this._element.style.getPropertyValue('--sticky-left') || '0px');
    }
    /**
     * @public
     */
    detach() {
        RendererServiceLocator.current.setStyle(this._element, 'position', '');
        RendererServiceLocator.current.setStyle(this._element, '--sticky-top', '');
        RendererServiceLocator.current.setStyle(this._element, '--sticky-left', '');
    }
}
class ScrollPositionStickyStrategy {
    // #region Fields
    _element;
    _scrollContainer;
    _scrollSubscription;
    // #endregion
    // #region Ctor
    constructor(element) {
        this._element = element;
        this._scrollSubscription = undefined;
    }
    // #endregion
    // #region Methods
    attach() {
        this._scrollContainer = ScrollerServiceLocator.current.tryFindScrollParent(this._element) ?? undefined;
        if (this._scrollContainer) {
            this._scrollSubscription = on(this._scrollContainer, 'scroll', () => this.handleScroll(), { passive: true });
        }
        this.handleScroll();
    }
    detach() {
        this._scrollSubscription?.dispose();
        this._scrollContainer = undefined;
    }
    handleScroll() {
        if (!this._scrollContainer) {
            return;
        }
        // const containerRect = this._scrollContainer.getBoundingClientRect();
        // const elementRect = this._element.getBoundingClientRect();
        const stickyOffset = parseInt(this._element.style.getPropertyValue('--sticky-top') || '0', 10);
        // const shouldStick = elementRect.top <= containerRect.top + stickyOffset;
        const scrollY = this._scrollContainer.scrollTop;
        const shouldStick = scrollY >= stickyOffset;
        // if (shouldStick !== this._lastStuck) {
        //     this._lastStuck = shouldStick;
        //     this._onStickyChange?.(shouldStick);
        if (shouldStick) {
            Object.assign(this._element.style, {
                position: 'fixed',
                top: scrollY + 'px',
                left: this._element.style.getPropertyValue('--sticky-left') || '0px',
                right: '0px',
                width: `${this._element.offsetWidth}px`
            });
        }
        else {
            Object.assign(this._element.style, {
                position: 'relative',
                top: '',
                left: '',
                right: '',
                width: ''
            });
        }
        // }
    }
}
//# sourceMappingURL=StickyController.js.map