<div
    x-data="{
        batch_size: 50,
        current_page: 0,
        endpoint: '',
        has_next: true,
        scroll_id: null,
        total_count: 0,

        is_loading: false,
        loaded_count: 0,
        loading_timer: null,
        observer: null,
        show_loading: false,

        async init() {
            this.scroll_id = $id('scroll');
            this.endpoint = this.$el.dataset.endpoint || '';
            this.batch_size = parseInt(this.$el.dataset.batchSize || '50');

            await this.$nextTick();

            if (this.$refs.scroll_container) {
                this.$refs.scroll_container.scrollTop = 0;
            }

            await this.load_more();

            if (this.has_next) {
                setTimeout(() => this.setup_observer(), 500);
            }
        },

        handle_item_mounted(event) {
            if (event.detail.scroll_id && event.detail.scroll_id !== this.scroll_id) {
                return;
            }
            this.loaded_count++;
        },

        handle_total_count_updated(event) {
            if (event.detail.scroll_id && event.detail.scroll_id !== this.scroll_id) {
                return;
            }

            this.total_count = event.detail.total_count;

            if (event.detail.batch_size) {
                this.batch_size = event.detail.batch_size;
            }
        },

        async load_more() {
            if (!this.endpoint || this.is_loading) {
                return;
            }

            this.is_loading = true;

            this.loading_timer = setTimeout(() => {
                this.show_loading = true;
            }, 200);

            let params = new URLSearchParams({
                page: this.current_page + 1,
                batch_size: this.batch_size
            });

            let separator = this.endpoint.includes('?') ? '&' : '?';
            let url = `${this.endpoint}${separator}${params}`;
            let view = new ViewGlue(url, {});

            let previous_count = this.loaded_count;

            await view.render_insert_adjacent(this.$refs.content_container, {}, 'beforeend');

            let added = this.loaded_count - previous_count;

            if (added > 0) {
                this.current_page++;
            }

            if (added < this.batch_size) {
                this.has_next = false;
                if (this.observer) {
                    this.observer.disconnect();
                }
            }

            if (this.loading_timer) {
                clearTimeout(this.loading_timer);
                this.loading_timer = null;
            }
            this.is_loading = false;
            this.show_loading = false;
        },

        setup_observer() {
            let trigger = this.$refs.infinite_scroll_trigger;

            if (!trigger) {
                return;
            }

            this.observer = new IntersectionObserver(
                (entries) => {
                    entries.forEach(async entry => {
                        if (entry.isIntersecting && this.has_next && !this.is_loading) {
                            await this.load_more();
                        }
                    });
                },
                { root: null, rootMargin: '200px', threshold: 0.01 }
            );

            this.observer.observe(trigger);
        },

        async reset_and_reload() {
            this.current_page = 0;
            this.has_next = true;
            this.loaded_count = 0;
            this.total_count = 0;

            this.$refs.content_container.innerHTML = '';

            if (this.observer) {
                this.observer.disconnect();
                this.observer = null;
            }

            await this.load_more();

            if (this.has_next) {
                setTimeout(() => this.setup_observer(), 500);
            }
        },
    }"
    data-batch-size="{{ batch_size|default:50 }}"
    data-endpoint="{{ endpoint }}"
    :data-scroll-id="scroll_id"
    @item-mounted.window="handle_item_mounted($event)"
    @total-count-updated.window="handle_total_count_updated($event)"
    @refresh-scroll.window="reset_and_reload()"
>
    <div class="position-relative" style="height: {{ scroll_height|default:'300px' }};">
        <div
            class="h-100"
            style="overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;"
            x-ref="scroll_container"
        >
            <div x-ref="content_container"></div>

            <div x-cloak x-show="show_loading" class="py-3 text-center">
                <div class="spinner-border text-app-primary" role="status"></div>
            </div>

            <div style="height: 10px;" x-ref="infinite_scroll_trigger"></div>
        </div>
    </div>

    {% include 'django_spire/infinite_scroll/element/footer.html' %}
</div>
