/**
 * 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 '../nile-icon';
import '../nile-button';
import './nile-carousel-item/nile-carousel-item';
import { html } from 'lit';
import { classMap } from 'lit/directives/class-map.js';
import { customElement, property, query, state } from 'lit/decorators.js';
import { map } from 'lit/directives/map.js';
import { range } from 'lit/directives/range.js';
import { prefersReducedMotion } from '../internal/animate';
import { watch } from '../internal/watch';
import { styles } from './nile-carousel.css';
import NileElement from '../internal/nile-element';
import { isCarouselItem, findMostVisibleSlide, getPageCount, getCurrentPage, canScrollNext, canScrollPrev, shouldSnapToSlide, scrollToSlide as scrollToSlideHelper, goToSlide as goToSlideHelper } from './carousel-helpers';
let NileCarousel = class NileCarousel extends NileElement {
    constructor() {
        super(...arguments);
        this.navigation = false;
        this.pagination = false;
        this.loop = false;
        this.navigationPosition = 'sides';
        this.slidesPerPage = 1;
        this.slidesPerMove = 1;
        this.activeSlide = 0;
        this.scrolling = false;
        this.pendingSlideChange = false;
        this.handleScroll = () => {
            if (!this.scrollContainer) {
                return;
            }
            this.scrolling = true;
            if (this.pendingSlideChange) {
                return;
            }
            const slides = this.getSlides();
            const mostVisibleSlide = findMostVisibleSlide(slides, this.scrollContainer);
            if (mostVisibleSlide) {
                const newActiveIndex = slides.indexOf(mostVisibleSlide);
                if (newActiveIndex !== -1 && newActiveIndex !== this.activeSlide) {
                    this.activeSlide = newActiveIndex;
                }
            }
        };
        this.handleScrollEnd = () => {
            this.scrolling = false;
            this.pendingSlideChange = false;
            if (this.scrollContainer) {
                const slides = this.getSlides();
                const mostVisibleSlide = findMostVisibleSlide(slides, this.scrollContainer);
                if (mostVisibleSlide) {
                    const newActiveIndex = slides.indexOf(mostVisibleSlide);
                    if (newActiveIndex !== -1 && newActiveIndex !== this.activeSlide) {
                        this.activeSlide = newActiveIndex;
                    }
                }
            }
        };
        this.handleSlotChange = () => {
            this.initializeSlides();
        };
    }
    connectedCallback() {
        super.connectedCallback();
        this.setAttribute('role', 'region');
        this.setAttribute('aria-label', 'carousel');
    }
    disconnectedCallback() {
        super.disconnectedCallback();
        this.mutationObserver?.disconnect();
    }
    firstUpdated() {
        this.initializeSlides();
        this.mutationObserver = new MutationObserver(this.handleSlotChange);
        this.mutationObserver.observe(this, {
            childList: true,
            subtree: true
        });
    }
    willUpdate(changedProperties) {
        if (changedProperties.has('slidesPerMove') || changedProperties.has('slidesPerPage')) {
            this.slidesPerMove = Math.min(this.slidesPerMove, this.slidesPerPage);
        }
    }
    getPageCount() {
        const slidesCount = this.getSlides().length;
        return getPageCount(slidesCount, this.slidesPerPage, this.slidesPerMove);
    }
    getCurrentPage() {
        return getCurrentPage(this.activeSlide, this.slidesPerMove);
    }
    canScrollNext() {
        return canScrollNext(this.getCurrentPage(), this.getPageCount(), this.loop);
    }
    canScrollPrev() {
        return canScrollPrev(this.getCurrentPage(), this.loop);
    }
    getSlides() {
        return [...this.children].filter((el) => isCarouselItem(el));
    }
    handleKeyDown(event) {
        if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End'].includes(event.key)) {
            const target = event.target;
            const isFocusInPagination = target.closest('.carousel__pagination-item') !== null;
            const isNext = event.key === 'ArrowDown' || event.key === 'ArrowRight';
            const isPrevious = event.key === 'ArrowUp' || event.key === 'ArrowLeft';
            event.preventDefault();
            if (isPrevious) {
                this.previous();
            }
            if (isNext) {
                this.next();
            }
            if (event.key === 'Home') {
                this.goToSlide(0);
            }
            if (event.key === 'End') {
                this.goToSlide(this.getSlides().length - 1);
            }
            if (isFocusInPagination) {
                this.updateComplete.then(() => {
                    const activePaginationItem = this.shadowRoot?.querySelector('.carousel__pagination-item--active');
                    if (activePaginationItem) {
                        activePaginationItem.focus();
                    }
                });
            }
        }
    }
    initializeSlides() {
        const slides = this.getSlides();
        if (!slides.length) {
            return;
        }
        slides.forEach((slide, i) => {
            slide.classList.toggle('--is-active', i === this.activeSlide);
        });
        this.updateSlidesSnap();
    }
    handleSlideChange() {
        const slides = this.getSlides();
        slides.forEach((slide, i) => {
            slide.classList.toggle('--is-active', i === this.activeSlide);
        });
        if (this.hasUpdated) {
            this.emit('nile-slide-change', {
                detail: {
                    index: this.activeSlide,
                    slide: slides[this.activeSlide]
                }
            });
        }
    }
    updateSlidesSnap() {
        const slides = this.getSlides();
        const slidesPerMove = this.slidesPerMove;
        slides.forEach((slide, i) => {
            if (shouldSnapToSlide(i, slidesPerMove)) {
                slide.style.removeProperty('scroll-snap-align');
            }
            else {
                slide.style.setProperty('scroll-snap-align', 'none');
            }
        });
    }
    previous(behavior = 'smooth') {
        const slides = this.getSlides();
        if (this.loop && this.activeSlide === 0) {
            this.goToSlide(slides.length - this.slidesPerMove, behavior);
        }
        else {
            this.goToSlide(this.activeSlide - this.slidesPerMove, behavior);
        }
    }
    next(behavior = 'smooth') {
        const slides = this.getSlides();
        const maxIndex = slides.length - this.slidesPerPage;
        if (this.loop && this.activeSlide >= maxIndex) {
            this.goToSlide(0, behavior);
        }
        else {
            this.goToSlide(this.activeSlide + this.slidesPerMove, behavior);
        }
    }
    goToSlide(index, behavior = 'smooth') {
        const { slidesPerPage } = this;
        const slides = this.getSlides();
        const result = goToSlideHelper(index, slides, slidesPerPage, behavior, this.loop);
        if (!result || !this.scrollContainer) {
            return;
        }
        this.activeSlide = result.newActiveSlide;
        const scrollBehavior = prefersReducedMotion() ? 'auto' : behavior;
        scrollToSlideHelper(result.slideToScroll, this.scrollContainer, scrollBehavior, (value) => {
            this.pendingSlideChange = value;
        });
    }
    renderNavigationButton(direction, enabled, onClick) {
        const isPrevious = direction === 'previous';
        const iconName = isPrevious
            ? 'var(--nile-icon-arrow-left, var(--ng-icon-arrow-narrow-left))'
            : 'var(--nile-icon-arrow-right, var(--ng-icon-arrow-narrow-right))';
        const slotName = isPrevious ? 'previous-icon' : 'next-icon';
        const partName = isPrevious ? 'navigation-button--previous' : 'navigation-button--next';
        const ariaLabel = isPrevious ? 'Previous slide' : 'Next slide';
        const isTopRight = this.navigationPosition === 'top-right';
        return html `
      <nile-button
        part="navigation-button ${partName}"
        class="${classMap({
            'carousel__navigation-button': true,
            [`carousel__navigation-button--${direction}`]: true,
            'carousel__navigation-button--disabled': !enabled
        })}"
        ?circle=${!isTopRight}
        variant="tertiary"
        ?disabled=${!enabled}
        aria-label="${ariaLabel}"
        aria-controls="scroll-container"
        @click=${enabled ? onClick : null}
      >
        <slot name="${slotName}">
          <nile-icon
            library="system"
            name="${iconName}"
          ></nile-icon>
        </slot>
      </nile-button>
    `;
    }
    renderScrollContainer() {
        return html `
      <div
        id="scroll-container"
        part="scroll-container"
        class="carousel__slides"
        style="--slides-per-page: ${this.slidesPerPage};"
        aria-busy="${this.scrolling ? 'true' : 'false'}"
        aria-atomic="true"
        tabindex="0"
        @keydown=${this.handleKeyDown}
        @scroll="${this.handleScroll}"
        @scrollend=${this.handleScrollEnd}
      >
        <slot></slot>
      </div>
    `;
    }
    renderPaginationItem(index, pagesCount, currentPage, slidesPerMove) {
        const isActive = index === currentPage;
        return html `
      <button
        part="pagination-item ${isActive ? 'pagination-item--active' : ''}"
        class="${classMap({
            'carousel__pagination-item': true,
            'carousel__pagination-item--active': isActive
        })}"
        role="tab"
        id="tab-${index + 1}"
        aria-controls="slide-${index + 1}"
        aria-selected="${isActive ? 'true' : 'false'}"
        aria-label="${isActive
            ? `Slide ${index + 1}`
            : `Go to slide ${index + 1} of ${pagesCount}`}"
        tabindex=${isActive ? '0' : '-1'}
        @click=${() => this.goToSlide(index * slidesPerMove)}
        @keydown=${this.handleKeyDown}
      ></button>
    `;
    }
    renderPagination() {
        if (!this.pagination) {
            return html ``;
        }
        const pagesCount = this.getPageCount();
        const currentPage = this.getCurrentPage();
        const slidesPerMove = this.slidesPerMove;
        return html `
      <div part="pagination" role="tablist" class="carousel__pagination">
        ${map(range(pagesCount), index => this.renderPaginationItem(index, pagesCount, currentPage, slidesPerMove))}
      </div>
    `;
    }
    render() {
        const prevEnabled = this.canScrollPrev();
        const nextEnabled = this.canScrollNext();
        const isTopRight = this.navigationPosition === 'top-right';
        return html `
      <div part="base" class="carousel">
        ${isTopRight && this.navigation ? html `
          <div class="carousel__navigation-wrapper--top-right">
            ${this.renderNavigationButton('previous', prevEnabled, () => this.previous())}
            ${this.renderNavigationButton('next', nextEnabled, () => this.next())}
          </div>
        ` : ''}
        <div class="carousel__content-wrapper">
          ${!isTopRight && this.navigation ? this.renderNavigationButton('previous', prevEnabled, () => this.previous()) : ''}
          ${this.renderScrollContainer()}
          ${!isTopRight && this.navigation ? this.renderNavigationButton('next', nextEnabled, () => this.next()) : ''}
        </div>
        ${this.renderPagination()}
      </div>
    `;
    }
};
NileCarousel.styles = [styles];
__decorate([
    property({ type: Boolean, reflect: true })
], NileCarousel.prototype, "navigation", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileCarousel.prototype, "pagination", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileCarousel.prototype, "loop", void 0);
__decorate([
    property({ type: String, attribute: 'navigation-position' })
], NileCarousel.prototype, "navigationPosition", void 0);
__decorate([
    property({ type: Number, attribute: 'slides-per-page' })
], NileCarousel.prototype, "slidesPerPage", void 0);
__decorate([
    property({ type: Number, attribute: 'slides-per-move' })
], NileCarousel.prototype, "slidesPerMove", void 0);
__decorate([
    query('.carousel__slides')
], NileCarousel.prototype, "scrollContainer", void 0);
__decorate([
    query('.carousel__pagination')
], NileCarousel.prototype, "paginationContainer", void 0);
__decorate([
    state()
], NileCarousel.prototype, "activeSlide", void 0);
__decorate([
    state()
], NileCarousel.prototype, "scrolling", void 0);
__decorate([
    watch('activeSlide')
], NileCarousel.prototype, "handleSlideChange", null);
__decorate([
    watch('slidesPerMove')
], NileCarousel.prototype, "updateSlidesSnap", null);
NileCarousel = __decorate([
    customElement('nile-carousel')
], NileCarousel);
export { NileCarousel };
export default NileCarousel;
//# sourceMappingURL=nile-carousel.js.map