
class CTLBModernVerticalTimeline {
      constructor(wrapper) {
        this.wrapper = wrapper;

        if(!wrapper){
            return;
        }

        // this.isLineFillingEnabled =
        //     ["yes", "true", "on"].includes(
        //         wrapper.getAttribute("data-line-filling")
        //     );

        const attrSource =
        wrapper.closest(".ctlb-wrapper[data-line-filling]") || wrapper;

    this.isLineFillingEnabled =
        ["yes", "true", "on", "1"].includes(
            (attrSource.getAttribute("data-line-filling") || "").toLowerCase()
        );


        this.init();
    }

    init() {
        this.moveTabContentsBasedOnScreen();
        // this.initTimelineWidget();
          this.initCtlbModernVertical();
           this.initBlockEditorAddStoryScroll();

        window.addEventListener("resize", () => {
            this.moveTabContentsBasedOnScreen();
            this.updateScrollAndTimeline();
            this.updateLineFillOnStoryChange();
        });
    }


   initBlockEditorAddStoryScroll() {

    // Only for Gutenberg editor
    const isBlockEditor =
        typeof wp !== "undefined" &&
        wp.data &&
        wp.data.select("core/block-editor");

    if (!isBlockEditor) return;

    const wrapper = this.wrapper;
    if (!wrapper) return;

    // ✅ SCOPE button to this block only
    const timelineBody = wrapper.closest('.cool-modern-vertical-timeline-body');
if (!timelineBody) return;

const addBtn = timelineBody.querySelector('.timeline-block-add-story button');
if (!addBtn) return;

    if (!addBtn) return;

    // ✅ prevent multiple bindings
    if (addBtn.__ctlbScrollInit) return;
    addBtn.__ctlbScrollInit = true;

    addBtn.addEventListener("click", () => {

        const observer = new MutationObserver(() => {
            const tabs = wrapper.querySelectorAll(
                ".ctlb-modern-vertical-timeline-tab-btn"
            );

            if (!tabs.length) return;

            const lastTab = tabs[tabs.length - 1];

        requestAnimationFrame(() => {
    lastTab.click(); 

    const scrollContainer = wrapper.querySelector(
        ".ctlb-modern-btn-wrapper"
    );

    if (scrollContainer) {
        scrollContainer.scrollTop =
            lastTab.offsetTop -
            scrollContainer.offsetTop;
    }

    this.updateScrollAndTimeline();
    this.updateLineFillOnStoryChange();
});


            observer.disconnect();
        });

        observer.observe(wrapper, {
            childList: true,
            subtree: true,
        });
    });
}


    updateScrollAndTimeline() {
    const wrapper = this.wrapper;
    if (!wrapper) return;

    const tabBtnWrapper = wrapper.querySelector(".ctlb-modern-btn-wrapper");
    const timelineLine = wrapper.querySelector(".ctlb-modern-vertical-line");
    const tabButtons = wrapper.querySelectorAll(".ctlb-modern-vertical-timeline-tab-btn");
    const tabMenu = wrapper.querySelector(".ctlb-modern-vertical-tab-menu");

    if (!tabBtnWrapper || !timelineLine || !tabMenu) return;

    // Only visible buttons (important for filters / year select)
    const visibleButtons = Array.from(tabButtons).filter(
        btn => btn.style.display !== "none"
    );

    if (visibleButtons.length === 0) return;

    /* ---------------------------------------------------
     * CASE 1: LESS THAN 3 ITEMS (short timeline)
     * --------------------------------------------------- */
    if (visibleButtons.length < 3) {
        timelineLine.style.top = "35px";
        timelineLine.style.height = "90%";

        const firstDot = visibleButtons[0].querySelector(".dot");
        if (firstDot) {
            const firstDotCenter =
                firstDot.offsetLeft + firstDot.offsetWidth / 2;
            timelineLine.style.left = `${firstDotCenter + 10}px`;
            timelineLine.style.transform = "translateX(-50%)";
        }
        return;
    }

    /* ---------------------------------------------------
     * CASE 2: NORMAL TIMELINE
     * --------------------------------------------------- */
    const firstDot = visibleButtons[0].querySelector(".dot");
    const lastDot =
        visibleButtons[visibleButtons.length - 1].querySelector(".dot");

    if (!firstDot || !lastDot) return;

    const wrapperRect = tabBtnWrapper.getBoundingClientRect();

    const topOffset =
        firstDot.getBoundingClientRect().top -
        wrapperRect.top +
        tabBtnWrapper.scrollTop +
        firstDot.offsetHeight / 2;

    const bottomOffset =
        lastDot.getBoundingClientRect().top -
        wrapperRect.top +
        tabBtnWrapper.scrollTop +
        lastDot.offsetHeight / 2;

    let height = Math.max(bottomOffset - topOffset, 0);

    /* ---------------------------------------------------
     * POSITION LINE HORIZONTALLY
     * --------------------------------------------------- */
    const firstDotCenter =
        firstDot.offsetLeft + firstDot.offsetWidth / 2;

    timelineLine.style.left = `${firstDotCenter + 10}px`;
    timelineLine.style.transform = "translateX(-50%)";
    timelineLine.style.top = `${topOffset}px`;

    /* ---------------------------------------------------
     * MOBILE + LAST TAB EXTENSION
     * --------------------------------------------------- */
    const isMobile = window.innerWidth < 700;
    const allButtons = wrapper.querySelectorAll(
        ".ctlb-modern-vertical-tab-btn"
    );

    let activeIndex = -1;
    for (let i = 0; i < allButtons.length; i++) {
        if (allButtons[i].classList.contains("active")) {
            activeIndex = i;
            break;
        }
    }

    const isLastTab = activeIndex === allButtons.length - 1;

    if (isMobile && isLastTab) {
        const lastVisibleContent = wrapper.querySelector(
            ".ctlb-modern-tab-content.active"
        );

        if (lastVisibleContent) {
            const contentRect =
                lastVisibleContent.getBoundingClientRect();
            const wrapperOuterRect = wrapper.getBoundingClientRect();

            const extraHeight =
                contentRect.bottom -
                wrapperOuterRect.top -
                topOffset;

            height += Math.max(extraHeight - 220, 0);
        }
    }

    timelineLine.style.height = `${height}px`;
}

 initCtlbModernVertical() {
    const wrapper = this.wrapper;
    const tabs = wrapper.querySelectorAll(
        ".ctlb-modern-vertical-timeline-tab-btn"
    );
    const contents = wrapper.querySelectorAll(
        ".ctlb-modern-tab-content"
    );
    const dots = wrapper.querySelectorAll(".dot");

    const tabBtnWrapper = wrapper.querySelector(".ctlb-modern-btn-wrapper");
    const scrollUpButton = wrapper.querySelector(".ctlb-scroll-up");
    const scrollDownButton = wrapper.querySelector(".ctlb-scroll-down");

    const isLoopScrollEnabled =
        wrapper.getAttribute("data-loop-scroll") === "yes";

        function updateScrollButtonsVisibility() {
    if (!scrollUpButton || !scrollDownButton) return;

    const visibleTabs = Array.from(tabs).filter(
        tab => tab.style.display !== "none"
    );

    const activeIndex = visibleTabs.findIndex(
        tab => tab.classList.contains("active")
    );

    if (!isLoopScrollEnabled) {
        const isAtTop = activeIndex === 0;
        const isAtBottom = activeIndex === visibleTabs.length - 1;

        if (visibleTabs.length <= 1 || activeIndex === -1) {
            scrollUpButton.classList.add("disabled");
            scrollDownButton.classList.add("disabled");
            return;
        }

        if (isAtTop) {
            scrollUpButton.classList.add("disabled");
        } else {
            scrollUpButton.classList.remove("disabled");
        }

        if (isAtBottom) {
            scrollDownButton.classList.add("disabled");
        } else {
            scrollDownButton.classList.remove("disabled");
        }
    } else {
        scrollUpButton.classList.remove("disabled");
        scrollDownButton.classList.remove("disabled");
    }
}


    /* ---------------- TAB CLICK ---------------- */
    tabs.forEach(tab => {
    tab.addEventListener("click", () => {
        const target = tab.dataset.target;
        if (!target) return;

        tabs.forEach(t => t.classList.remove("active"));
        contents.forEach(c => c.classList.remove("active"));
        dots.forEach(d => d.classList.remove("active-dot"));

        tab.classList.add("active");

        const dot = tab.querySelector(".dot");
        if (dot) dot.classList.add("active-dot");

        wrapper
            .querySelectorAll(`.ctlb-modern-tab-content[data-block-id="${target}"]`)
            .forEach(c => c.classList.add("active"));

        this.updateScrollAndTimeline();
        this.updateLineFillOnStoryChange();

        wrapper.dispatchEvent(
            new CustomEvent("ctlb:tabChanged", { detail: { target } })
        );
    });
});


    /* ---------------- SCROLL UP ---------------- */
if (scrollUpButton) {

    // ✅ remove old handler if it exists
    if (scrollUpButton._clickHandler) {
        scrollUpButton.removeEventListener(
            "click",
            scrollUpButton._clickHandler
        );
    }

    scrollUpButton._clickHandler = () => {
        const visibleTabs = [...tabs].filter(
            t => t.style.display !== "none"
        );

        const activeIndex = visibleTabs.findIndex(t =>
            t.classList.contains("active")
        );

        if (activeIndex === -1) return;

        let prevIndex = activeIndex - 1;

        if (prevIndex < 0) {
            if (isLoopScrollEnabled) {
                prevIndex = visibleTabs.length - 1;
            } else {
                return;
            }
        }

        visibleTabs[prevIndex].click();

        tabBtnWrapper.scrollTop =
            visibleTabs[prevIndex].offsetTop -
            tabBtnWrapper.offsetTop;

        updateScrollButtonsVisibility();
    };

    scrollUpButton.addEventListener(
        "click",
        scrollUpButton._clickHandler
    );
}



    /* ---------------- SCROLL DOWN ---------------- */
if (scrollDownButton) {

    // ✅ remove old handler if it exists
    if (scrollDownButton._clickHandler) {
        scrollDownButton.removeEventListener(
            "click",
            scrollDownButton._clickHandler
        );
    }

    scrollDownButton._clickHandler = () => {
        const visibleTabs = [...tabs].filter(
            t => t.style.display !== "none"
        );

        const activeIndex = visibleTabs.findIndex(t =>
            t.classList.contains("active")
        );

        if (activeIndex === -1) return;

        let nextIndex = activeIndex + 1;

        if (nextIndex >= visibleTabs.length) {
            if (isLoopScrollEnabled) {
                nextIndex = 0;
            } else {
                return;
            }
        }

        visibleTabs[nextIndex].click();

        tabBtnWrapper.scrollTop =
            visibleTabs[nextIndex].offsetTop -
            tabBtnWrapper.offsetTop;

        updateScrollButtonsVisibility();
    };

    scrollDownButton.addEventListener(
        "click",
        scrollDownButton._clickHandler
    );
}


/* ---------------- YEAR SELECT ---------------- */
const yearSelect = wrapper.querySelector("#ctlbyearSelect");
if (yearSelect) {
    const yearSet = new Set();

    tabs.forEach(btn => {
        const year = btn.getAttribute("data-year");
        if (year) yearSet.add(year); 
    });

    const years = Array.from(yearSet).sort(); 

    // Populate select
    yearSelect.innerHTML = '<option value="all">All</option>';
    years.forEach(year => {
        const option = document.createElement("option");
        option.value = year;
        option.textContent = year;
        yearSelect.appendChild(option);
    });

    // ---------------- FILTER LOGIC ----------------
    yearSelect.addEventListener("change", () => {
        const selectedYear = yearSelect.value;
        let firstVisibleTab = null;

        tabs.forEach(btn => {
            const year = btn.getAttribute("data-year");

            if (selectedYear === "all" || year === selectedYear) {
                btn.style.display = "block";
                if (!firstVisibleTab) firstVisibleTab = btn;
            } else {
                btn.style.display = "none";
            }
        });

        // Reset active states
        tabs.forEach(t => t.classList.remove("active"));
        contents.forEach(c => c.classList.remove("active"));
        dots.forEach(d => d.classList.remove("active-dot"));

        tabBtnWrapper.scrollTop = 0;

        if (firstVisibleTab) {
            requestAnimationFrame(() => {
                firstVisibleTab.click();
                requestAnimationFrame(() => {
                    this.updateScrollAndTimeline();
                    this.updateLineFillOnStoryChange();
                });
            });
        } else {
            this.updateScrollAndTimeline();
            this.updateLineFillOnStoryChange();
            updateScrollButtonsVisibility();
        }
    });
}
/* ---------------- YEAR NAV TOGGLE RESET ---------------- */
const isYearNavEnabled = wrapper.getAttribute("data-year-nav") === "true";

if (!isYearNavEnabled) {
    tabs.forEach(tab => {
        tab.style.display = ""; // restore default
    });
}


    /* ---------------- MOUSE WHEEL ---------------- */
if (tabBtnWrapper) {

    if (tabBtnWrapper._wheelHandler) {
        tabBtnWrapper.removeEventListener(
            "wheel",
            tabBtnWrapper._wheelHandler,
            { passive: false }
        );
    }

    let scrollTimeout;

    tabBtnWrapper._wheelHandler = (e) => {
        e.preventDefault();

        clearTimeout(scrollTimeout);

        scrollTimeout = setTimeout(() => {
            const visibleTabs = [...tabs].filter(
                t => t.style.display !== "none"
            );

            const activeIndex = visibleTabs.findIndex(t =>
                t.classList.contains("active")
            );

            if (activeIndex === -1) return;

            let nextIndex = activeIndex;

            if (e.deltaY > 0) nextIndex++;
            if (e.deltaY < 0) nextIndex--;

            if (isLoopScrollEnabled) {
                if (nextIndex < 0) nextIndex = visibleTabs.length - 1;
                if (nextIndex >= visibleTabs.length) nextIndex = 0;
            }

            if (visibleTabs[nextIndex]) {
                visibleTabs[nextIndex].click();
                tabBtnWrapper.scrollTop =
                    visibleTabs[nextIndex].offsetTop -
                    tabBtnWrapper.offsetTop;

                updateScrollButtonsVisibility();
            }
        }, 100);
    };

    tabBtnWrapper.addEventListener(
        "wheel",
        tabBtnWrapper._wheelHandler,
        { passive: false }
    );

    if (!tabBtnWrapper._scrollHandler) {
        tabBtnWrapper._scrollHandler = () => {
            this.updateLineFillOnStoryChange();
        };
        tabBtnWrapper.addEventListener("scroll", tabBtnWrapper._scrollHandler);
    }
}

    requestAnimationFrame(() => {
    const firstVisibleTab = [...tabs].find(
        t => t.style.display !== "none"
    );
    if (!firstVisibleTab) return;

    const hasActive = [...tabs].some(t =>
        t.classList.contains("active")
    );
    if (hasActive) return;

    firstVisibleTab.click();
});


    /* ---------------- DEFAULT ACTIVE (Frontend only) ---------------- */
requestAnimationFrame(() => {
    document.querySelectorAll('.ctlb-wrapper').forEach(wrapper => {
        const tabs = wrapper.querySelectorAll('.ctlb-modern-vertical-timeline-tab-btn');
        const contents = wrapper.querySelectorAll('.ctlb-modern-tab-content');

        if (!wrapper.dataset.init && tabs[0] && contents[0]) {
            tabs[0].classList.add('active');
            contents[0].classList.add('active');

            wrapper.dataset.init = 'true';
        }
    });
});
}



   updateLineFillOnStoryChange() {
    if (!this.isLineFillingEnabled) return;
    const wrapper = this.wrapper;
    if (!wrapper) return;

    const lineOuter = wrapper.querySelector(".ctlb-modern-vertical-line");
    const lineInner = wrapper.querySelector(".ctlb-line-fill");

    if (!lineOuter || !lineInner) return;

    // Only visible tabs (important for year filter)
    const visibleTabs = Array.from(
        wrapper.querySelectorAll(".ctlb-modern-vertical-timeline-tab-btn")
    ).filter(tab => tab.style.display !== "none");

    if (!visibleTabs.length) return;

    const activeIndex = visibleTabs.findIndex(tab =>
        tab.classList.contains("active")
    );

    if (activeIndex === -1) return;

    const totalTabs = visibleTabs.length;
    const outerHeight = lineOuter.offsetHeight;

    let fillHeight;

    if (totalTabs <= 1) {
        fillHeight = outerHeight;
    } else {
        const progress = activeIndex / (totalTabs - 1);
        fillHeight = outerHeight * progress + 100; 
    }

    
    lineInner.style.height =
        Math.min(fillHeight, outerHeight) + "px";
}


moveTabContentsBasedOnScreen() {
    const wrapper = this.wrapper;
    if (!wrapper) return;

    const isDesktop = window.innerWidth >= 700;

    const desktopBox = wrapper.querySelector(".ctlb-modern-content-box");
    if (!desktopBox) return;

    const contents = wrapper.querySelectorAll(".ctlb-modern-tab-content");

    contents.forEach(content => {
        const blockId = content.getAttribute("data-block-id");
        if (!blockId) return;

        const tabBtn = wrapper.querySelector(
            `.ctlb-modern-vertical-timeline-tab-btn[data-target="${blockId}"]`
        );

        if (!tabBtn) return;

        const alreadyInDesktopBox = desktopBox.contains(content);

        if (isDesktop) {
            if (!alreadyInDesktopBox) {
                desktopBox.appendChild(content);
            }
        } else {
            const nextEl = tabBtn.nextElementSibling;
            if (nextEl !== content) {
                tabBtn.parentNode.insertBefore(content, nextEl);
            }
        }
    });

    requestAnimationFrame(() => {
        this.updateScrollAndTimeline();
        this.updateLineFillOnStoryChange();
    });
}


}

jQuery(document).ready(() => {
    document
        .querySelectorAll(".ctlb-modern-vertical-timeline-tab-container")
        .forEach(wrapper => {
            if (!wrapper.__ctlbInit) {
                wrapper.__ctlbInit = true;
                new CTLBModernVerticalTimeline(wrapper);
            }
        });
});

