import { subscribeSelector, shallowEqual } from "../../framework/selectors";
import { getPointsToPixels } from "../state";
import { getDevicePixelRatio } from "../layout";
function selectThumbnailSlice(state) {
    return {
        docId: state.doc?.id ?? null,
        pageCount: state.pageCount,
        pageInfos: state.pageInfos,
        currentPage: state.page,
        dpi: state.dpi,
        thumbnailWidth: state.thumbnailWidth,
    };
}
export function createThumbnailPanel() {
    const el = document.createElement("div");
    el.className = "udoc-thumbnail-panel";
    el.setAttribute("role", "listbox");
    el.setAttribute("aria-label", "Page thumbnails");
    el.setAttribute("tabindex", "0");
    /** Keyboard-focused page (for arrow key navigation, independent of current page) */
    let focusedPage = 1;
    el.addEventListener("keydown", (e) => {
        if (!storeRef || thumbnailItems.length === 0)
            return;
        let handled = true;
        switch (e.key) {
            case "ArrowDown":
                focusedPage = Math.min(focusedPage + 1, thumbnailItems.length);
                break;
            case "ArrowUp":
                focusedPage = Math.max(focusedPage - 1, 1);
                break;
            case "Home":
                focusedPage = 1;
                break;
            case "End":
                focusedPage = thumbnailItems.length;
                break;
            case "Enter":
            case " ":
                storeRef.dispatch({ type: "NAVIGATE_TO_PAGE", page: focusedPage });
                break;
            default:
                handled = false;
        }
        if (handled) {
            e.preventDefault();
            el.setAttribute("aria-activedescendant", `udoc-thumb-${focusedPage}`);
            const item = thumbnailItems[focusedPage - 1];
            if (item) {
                item.container.scrollIntoView({ block: "nearest", behavior: "instant" });
            }
        }
    });
    let mounted = false;
    let storeRef = null;
    let workerClient = null;
    let i18nRef = null;
    let thumbnailItems = [];
    let intersectionObserver = null;
    let currentSlice = null;
    let unsubRender = null;
    const unsubEvents = [];
    function createThumbnailItem(pageNumber, pageInfo, thumbnailWidth) {
        const container = document.createElement("div");
        container.className = "udoc-thumbnail-item";
        container.dataset.page = String(pageNumber);
        container.setAttribute("role", "option");
        container.setAttribute("aria-label", i18nRef ? i18nRef.t("thumbnails.pageLabel", { page: pageNumber }) : `Page ${pageNumber}`);
        container.id = `udoc-thumb-${pageNumber}`;
        const canvas = document.createElement("canvas");
        canvas.className = "udoc-thumbnail-item__canvas";
        canvas.setAttribute("aria-hidden", "true");
        // Set aspect ratio for responsive scaling
        const aspectRatio = pageInfo.width / pageInfo.height;
        canvas.style.aspectRatio = String(aspectRatio);
        canvas.style.width = `${thumbnailWidth}px`;
        container.appendChild(canvas);
        const label = document.createElement("div");
        label.className = "udoc-thumbnail-item__label";
        label.textContent = String(pageNumber);
        container.appendChild(label);
        // Click handler for navigation
        const onClick = () => {
            if (storeRef) {
                storeRef.dispatch({ type: "NAVIGATE_TO_PAGE", page: pageNumber });
            }
        };
        container.addEventListener("click", onClick);
        unsubEvents.push(() => container.removeEventListener("click", onClick));
        return {
            container,
            canvas,
            pageNumber,
            renderKey: "",
            pendingKey: null,
            renderToken: 0,
        };
    }
    function buildThumbnailList(slice) {
        // Clear existing
        for (const item of thumbnailItems) {
            item.container.remove();
        }
        thumbnailItems = [];
        if (!slice.docId || slice.pageCount === 0)
            return;
        // Default page size if not available
        const defaultPageInfo = { width: 612, height: 792, rotation: 0 };
        // Create thumbnail items for each page
        for (let i = 1; i <= slice.pageCount; i++) {
            const pageInfo = slice.pageInfos[i - 1] || defaultPageInfo;
            const item = createThumbnailItem(i, pageInfo, slice.thumbnailWidth);
            thumbnailItems.push(item);
            el.appendChild(item.container);
        }
        // Setup intersection observer for lazy loading
        setupIntersectionObserver();
        // Highlight current page and scroll it into view
        updateCurrentPageHighlight(slice.currentPage);
        scrollActiveIntoView(slice.currentPage);
    }
    function setupIntersectionObserver() {
        if (intersectionObserver) {
            intersectionObserver.disconnect();
        }
        intersectionObserver = new IntersectionObserver((entries) => {
            for (const entry of entries) {
                if (entry.isIntersecting) {
                    const pageNumber = parseInt(entry.target.dataset.page || "0", 10);
                    if (pageNumber > 0) {
                        requestThumbnailRender(pageNumber);
                    }
                }
            }
        }, {
            root: el,
            rootMargin: "100px 0px",
            threshold: 0,
        });
        for (const item of thumbnailItems) {
            intersectionObserver.observe(item.container);
        }
        // Setup scroll handler for boost priority
        setupScrollHandler();
    }
    function setupScrollHandler() {
        const onScroll = () => {
            if (!workerClient || !currentSlice?.docId)
                return;
            const focusPage = findFocusThumbnail();
            if (focusPage !== null) {
                workerClient.boostThumbnailRenderPriority(currentSlice.docId, focusPage);
            }
        };
        el.addEventListener("scroll", onScroll, { passive: true });
        unsubEvents.push(() => el.removeEventListener("scroll", onScroll));
    }
    function findFocusThumbnail() {
        if (thumbnailItems.length === 0)
            return null;
        const panelRect = el.getBoundingClientRect();
        const panelCenter = panelRect.top + panelRect.height / 2;
        let closestPage = null;
        let closestDistance = Infinity;
        for (const item of thumbnailItems) {
            const itemRect = item.container.getBoundingClientRect();
            const itemCenter = itemRect.top + itemRect.height / 2;
            const distance = Math.abs(itemCenter - panelCenter);
            if (distance < closestDistance) {
                closestDistance = distance;
                closestPage = item.pageNumber;
            }
        }
        return closestPage;
    }
    async function requestThumbnailRender(pageNumber) {
        const item = thumbnailItems[pageNumber - 1];
        if (!item || !workerClient || !currentSlice || !currentSlice.docId)
            return;
        const pageInfo = currentSlice.pageInfos[pageNumber - 1];
        if (!pageInfo)
            return;
        const dpr = getDevicePixelRatio();
        const pointsToPixels = getPointsToPixels(currentSlice.dpi);
        const scale = currentSlice.thumbnailWidth / (pageInfo.width * pointsToPixels);
        const renderScale = scale * pointsToPixels * dpr;
        const key = `${currentSlice.docId}:${pageNumber}:${renderScale.toFixed(4)}`;
        if (item.renderKey === key || item.pendingKey === key)
            return;
        const token = ++item.renderToken;
        item.pendingKey = key;
        try {
            const result = await workerClient.requestRender({
                docId: currentSlice.docId,
                page: pageNumber,
                type: "thumbnail",
                scale: renderScale,
            });
            if (!mounted || item.renderToken !== token) {
                if (item.pendingKey === key)
                    item.pendingKey = null;
                return;
            }
            const canvas = item.canvas;
            if (canvas.width !== result.width)
                canvas.width = result.width;
            if (canvas.height !== result.height)
                canvas.height = result.height;
            const ctx = canvas.getContext("2d");
            if (ctx) {
                ctx.drawImage(result.bitmap, 0, 0);
            }
            item.renderKey = key;
        }
        catch (error) {
            if (!(error instanceof Error && error.message === "Request cancelled")) {
                console.error(`Thumbnail render failed for page ${pageNumber}:`, error);
            }
        }
        finally {
            if (item.pendingKey === key)
                item.pendingKey = null;
        }
    }
    function updateCurrentPageHighlight(currentPage) {
        for (const item of thumbnailItems) {
            const isActive = item.pageNumber === currentPage;
            item.container.classList.toggle("udoc-thumbnail-item--active", isActive);
            item.container.setAttribute("aria-selected", String(isActive));
        }
        el.setAttribute("aria-activedescendant", `udoc-thumb-${currentPage}`);
        focusedPage = currentPage;
    }
    function scrollActiveIntoView(currentPage) {
        const item = thumbnailItems[currentPage - 1];
        if (!item)
            return;
        // Use instant scroll to avoid triggering renders for all intermediate thumbnails
        item.container.scrollIntoView({
            behavior: "instant",
            block: "nearest",
        });
    }
    function applyState(slice) {
        const docChanged = !currentSlice ||
            slice.docId !== currentSlice.docId ||
            slice.pageCount !== currentSlice.pageCount ||
            slice.pageInfos !== currentSlice.pageInfos ||
            slice.thumbnailWidth !== currentSlice.thumbnailWidth;
        if (docChanged) {
            buildThumbnailList(slice);
        }
        else if (slice.currentPage !== currentSlice?.currentPage) {
            updateCurrentPageHighlight(slice.currentPage);
            scrollActiveIntoView(slice.currentPage);
        }
        currentSlice = slice;
    }
    function mount(container, store, rm, i18n) {
        container.appendChild(el);
        mounted = true;
        storeRef = store;
        workerClient = rm;
        i18nRef = i18n;
        el.setAttribute("aria-label", i18n.t("thumbnails.label"));
        // Apply initial state (currentSlice is null, so docChanged will be true)
        applyState(selectThumbnailSlice(store.getState()));
        unsubRender = subscribeSelector(store, selectThumbnailSlice, applyState, { equality: shallowEqual });
    }
    function destroy() {
        mounted = false;
        if (unsubRender)
            unsubRender();
        for (const off of unsubEvents)
            off();
        unsubEvents.length = 0;
        if (intersectionObserver) {
            intersectionObserver.disconnect();
            intersectionObserver = null;
        }
        thumbnailItems = [];
        storeRef = null;
        workerClient = null;
        currentSlice = null;
        el.remove();
    }
    return { el, mount, destroy };
}
//# sourceMappingURL=ThumbnailPanel.js.map