/**
 * Copyright Aquera Inc 2025
 *
 * This source code is licensed under the BSD-3-Clause license found in the
 * LICENSE file in the root directory of this source tree.
 */
import { __decorate } from "tslib";
import { html } from 'lit';
import { customElement, property, query, state } from 'lit/decorators.js';
import { styles } from './nile-grid.css';
import NileElement from '../internal/nile-element';
import { syncStickyShadows, layout } from './nile-grid.layout';
import { listenToEventListeners, removeEventListeners, getHead, getBody, copyArrayValuesInPlace } from './nile-grid.utils';
import { computeNewWidth, resizeWithScroll, resizeNoScroll, updateResizeGuides } from './nile-grid.resize';
/**
 * Nile grid component.
 *
 * @tag nile-grid
 *
 */
let NileGrid = class NileGrid extends NileElement {
    /**
     * The styles for nile-grid
     * @remarks If you are extending this class you can extend the base styles with super. Eg `return [super(), myCustomStyles]`
     */
    static get styles() {
        return [styles];
    }
    constructor() {
        super();
        /** To store the column widths in the beginning and after resizing */
        this.columnWidths = [];
        /** To enable horizontal scrolling when user is resizing */
        this.enableScroll = false;
        /** To enable hoverable rows */
        this.hoverable = false;
        /** Controls vertical overscroll behavior when the grid is scrollable. */
        this.overflowScrollBehaviour = "none";
        /** To store the request animation frame */
        this.raf = 0;
        /** Minimum column width */
        this.minColumnWidth = 40;
        /** To store the sticky index's */
        this.stickyLeftIndexes = [];
        /** To store the sticky index's */
        this.stickyRightIndexes = [];
        /** To calculate the rowspan height */
        this.cellHeight = null;
        this.headHeight = null;
        /** To check if the widths are initialized */
        this.widthsInitialized = false;
        /** To check if the widths are initialized */
        this.lockedWidthColumns = [];
        /** prefix columns width */
        this.prefixSumColumnsWidth = [];
        /** prefix columns width */
        this.stickyColumns = [];
        /** body rows */
        this.bodyRows = [];
        /** head rows */
        this.headRows = [];
        this.needsStructureLayout = false;
        this.needsWidthLayout = false;
        this.needsSpanLayout = false;
        this.colCount = 0;
        this.isGridReady = false;
        this.stickyLeftHeadEls = [];
        this.stickyRightHeadEls = [];
        this.stickyLeftBodyEls = [];
        this.stickyRightBodyEls = [];
        this.resizeTimer = 0;
        /** To throttle sticky shadow updates */
        this.shadowRaf = 0;
        this.resizeBaseColumnWidths = [];
        this.syncStickyShadowsRaf = () => {
            if (this.shadowRaf)
                return;
            this.shadowRaf = requestAnimationFrame(() => {
                this.shadowRaf = 0;
                syncStickyShadows(this);
            });
        };
        this.onResize = (e) => {
            e.stopPropagation();
            this.emit('nile-resize', {
                columnNumber: e.detail.col,
                columnWidth: e.detail.widthPx,
            });
            const { col, widthPx } = e.detail;
            if (!this.resizeBaseColumnWidths)
                return;
            copyArrayValuesInPlace(this.columnWidths, this.resizeBaseColumnWidths);
            const { prevW, newW, delta0 } = computeNewWidth({
                target: e.target,
                col,
                widthPx,
                floor: this.minColumnWidth,
                columnWidths: this.columnWidths,
            });
            if (delta0 === 0) {
                updateResizeGuides(this, col);
                return;
            }
            if (!this.enableScroll) {
                resizeNoScroll({ grid: this, col, prevW, newW, floor: this.minColumnWidth });
            }
            else {
                resizeWithScroll({ grid: this, col, newW });
            }
            updateResizeGuides(this, col);
        };
    }
    connectedCallback() {
        super.connectedCallback();
        this.emit('nile-init');
    }
    updateOverscrollBehavior() {
        const isVerticallyScrollable = this.scrollHeight > this.clientHeight;
        this.style.overscrollBehavior = isVerticallyScrollable
            ? this.overflowScrollBehaviour
            : '';
    }
    scheduleLayout() {
        if (this.raf)
            cancelAnimationFrame(this.raf);
        this.raf = requestAnimationFrame(() => {
            this.raf = 0;
            layout(this, this.slotEl, this.ensureWidths.bind(this), this.stickyLeftIndexes, this.stickyRightIndexes);
            syncStickyShadows(this);
        });
    }
    ensureWidths(colCount) {
        if (this.columnWidths.length !== colCount) {
            this.columnWidths = Array(colCount).fill(0);
            this.lockedWidthColumns = Array(colCount).fill(false);
        }
    }
    firstUpdated() {
        this.setAttribute('role', 'table');
        listenToEventListeners(this, this.onResize, this.slotEl, this._attachObserverAndLayout.bind(this));
        this.addEventListener('scroll', this.syncStickyShadowsRaf);
        this.resizeObserverStickyShadows = new ResizeObserver(() => {
            syncStickyShadows(this);
            this.updateOverscrollBehavior();
        });
        this.resizeObserverStickyShadows.observe(this);
        this.syncStickyShadowsRaf();
    }
    updated(changed) {
        if (changed.has("overflowScrollBehaviour")) {
            this.updateOverscrollBehavior();
        }
    }
    _attachObserverAndLayout() {
        this.mo?.disconnect();
        this.mo = new MutationObserver(() => {
            this.needsStructureLayout = true;
            this.needsWidthLayout = true;
            this.needsSpanLayout = true;
            this.scheduleLayout();
        });
        this.resizeObserver?.disconnect();
        this.resizeObserver = new ResizeObserver(() => {
            if (this.resizeTimer)
                clearTimeout(this.resizeTimer);
            this.resizeTimer = setTimeout(() => {
                this.resizeTimer = 0;
                this.needsWidthLayout = true;
                this.scheduleLayout();
            }, 16);
        });
        const head = getHead(this.slotEl);
        const body = getBody(this.slotEl);
        if (!head && !body)
            return;
        const target = head ?? this;
        this.mo.observe(target, {
            childList: true,
            subtree: true,
            attributes: true,
            attributeFilter: ['colspan', 'rowspan', 'width', 'lockwidth', 'sticky']
        });
        this.resizeObserver?.observe(this);
        if (!this.colCount || !this.columnWidths?.length) {
            this.needsStructureLayout = true;
            this.needsSpanLayout = true;
            this.needsWidthLayout = true;
            this.scheduleLayout();
        }
    }
    render() {
        return html `
      <div part="grid-base" class="nile-grid-base">
        <div part="grid-slot-wrapper">
          <slot part="grid-slot"></slot>
        </div>
        <div part="resize-start" class="nile-resize-start"></div>
        <div part="resize-end" class="nile-resize-end"></div>
      </div>
    `;
    }
    disconnectedCallback() {
        this.emit('nile-destroy');
        super.disconnectedCallback?.();
        this.mo?.disconnect();
        this.resizeObserver?.disconnect();
        this.resizeObserverStickyShadows?.disconnect();
        if (this.raf)
            cancelAnimationFrame(this.raf);
        removeEventListeners(this, this.onResize, this.slotEl, this._attachObserverAndLayout.bind(this));
    }
};
__decorate([
    state()
], NileGrid.prototype, "columnWidths", void 0);
__decorate([
    query('slot')
], NileGrid.prototype, "slotEl", void 0);
__decorate([
    query('.nile-resize-start')
], NileGrid.prototype, "resizeStart", void 0);
__decorate([
    query('.nile-resize-end')
], NileGrid.prototype, "resizeEnd", void 0);
__decorate([
    query('.shadow-left')
], NileGrid.prototype, "shadowLeft", void 0);
__decorate([
    query('.shadow-right')
], NileGrid.prototype, "shadowRight", void 0);
__decorate([
    property({ type: Boolean, attribute: true, reflect: true })
], NileGrid.prototype, "enableScroll", void 0);
__decorate([
    property({ type: Boolean, attribute: true, reflect: true })
], NileGrid.prototype, "hoverable", void 0);
__decorate([
    property({ type: String, attribute: true, reflect: true })
], NileGrid.prototype, "overflowScrollBehaviour", void 0);
__decorate([
    property({ type: Number, reflect: true, attribute: true })
], NileGrid.prototype, "minColumnWidth", void 0);
__decorate([
    state()
], NileGrid.prototype, "stickyLeftIndexes", void 0);
__decorate([
    state()
], NileGrid.prototype, "stickyRightIndexes", void 0);
__decorate([
    state()
], NileGrid.prototype, "cellHeight", void 0);
__decorate([
    state()
], NileGrid.prototype, "headHeight", void 0);
__decorate([
    state()
], NileGrid.prototype, "widthsInitialized", void 0);
__decorate([
    state()
], NileGrid.prototype, "lockedWidthColumns", void 0);
__decorate([
    state()
], NileGrid.prototype, "prefixSumColumnsWidth", void 0);
__decorate([
    state()
], NileGrid.prototype, "stickyColumns", void 0);
__decorate([
    state()
], NileGrid.prototype, "bodyRows", void 0);
__decorate([
    state()
], NileGrid.prototype, "headRows", void 0);
__decorate([
    state()
], NileGrid.prototype, "needsStructureLayout", void 0);
__decorate([
    state()
], NileGrid.prototype, "needsWidthLayout", void 0);
__decorate([
    state()
], NileGrid.prototype, "needsSpanLayout", void 0);
__decorate([
    state()
], NileGrid.prototype, "colCount", void 0);
NileGrid = __decorate([
    customElement('nile-grid')
], NileGrid);
export { NileGrid };
export default NileGrid;
//# sourceMappingURL=nile-grid.js.map