function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }

function getEl(id) { return typeof id === "string" ? document.getElementById(id) : id; }

export function getVisibleIds(containerSelector) {
    console.info("getVisibleIds " + containerSelector);

    const container = document.getElementById(containerSelector);
    if (!container) {
        return {
            visibleIds: [],
            isAtLeft: true,
            isAtRight: true
        };
    }

    const scrollLeft = container.scrollLeft;
    const clientWidth = container.clientWidth;
    const scrollWidth = container.scrollWidth;

    // Small tolerance for fractional pixels
    const epsilon = 1;

    const isAtLeft = scrollLeft <= epsilon;
    const isAtRight = scrollLeft + clientWidth >= scrollWidth - epsilon;

    const scrollRight = scrollLeft + clientWidth;
    const cRect = container.getBoundingClientRect();

    const elements = container.querySelectorAll(".scroll-anchor");
    const visibleIds = [];

    elements.forEach(el => {
        const id = el.getAttribute("data-id");
        if (!id) return;

        const elRect = el.getBoundingClientRect();

        // Position relative to scrollable content
        const elLeft = elRect.left - cRect.left + scrollLeft;
        const elRight = elLeft + el.offsetWidth;

        const fullyVisible = elLeft >= scrollLeft && elRight <= scrollRight;

        if (fullyVisible) {
            visibleIds.push(id);
        }
    });

    return {
        visibleIds,
        isAtLeft,
        isAtRight
    };
}

function isVisibleInContainer(container, el) {
    if (!container || !el) return false;
    const c = container.getBoundingClientRect();
    const r = el.getBoundingClientRect();
    return r.right > c.left && r.left < c.right;
}

export function scrollIntoView(el, options) {
    if (!el) return;
    if (el.scrollIntoView) {
        try {
            el.scrollIntoView(options || { behavior: "auto", block: "nearest", inline: "nearest" });
        } catch {
            el.scrollIntoView(true);
        }
    }
}

export async function scrollUntilVisible(containerId, targetSelector, opts) {
    const container = getEl(containerId);
    if (!container) return { found: false, reachedEnd: false, steps: 0, pos: 0, reason: "no-container" };

    const {
        stepPx = Math.floor(container.clientWidth * 0.8),
        waitPerStepMs = 60,
        maxSteps = 250,
        direction = "forward"
    } = opts || {};

    const step = Math.max(1, stepPx) * (direction === "backward" ? -1 : 1);

    let candidate = document.querySelector(targetSelector);
    if (candidate && isVisibleInContainer(container, candidate)) {
        return { found: true, reachedEnd: false, steps: 0, pos: container.scrollLeft, reason: "already-visible" };
    }

    let steps = 0;
    let lastPos = -1;
    let stuckCount = 0;

    while (steps < maxSteps) {
        const maxLeft = container.scrollWidth - container.clientWidth;
        const atEndForward = container.scrollLeft >= (maxLeft - 1);
        const atEndBackward = container.scrollLeft <= 0;

        if ((direction === "forward" && atEndForward) || (direction === "backward" && atEndBackward)) {
            await sleep(waitPerStepMs);
            candidate = document.querySelector(targetSelector);
            if (candidate && isVisibleInContainer(container, candidate)) {
                return { found: true, reachedEnd: true, steps, pos: container.scrollLeft, reason: "found-at-end" };
            }
            return { found: false, reachedEnd: true, steps, pos: container.scrollLeft, reason: "end-reached" };
        }

        container.scrollLeft = Math.min(Math.max(0, container.scrollLeft + step), maxLeft);
        steps++;

        await sleep(waitPerStepMs);

        candidate = document.querySelector(targetSelector);
        if (candidate && isVisibleInContainer(container, candidate)) {
            return { found: true, reachedEnd: false, steps, pos: container.scrollLeft, reason: "found" };
        }

        const pos = container.scrollLeft;
        if (pos === lastPos) {
            stuckCount++;
            if (stuckCount >= 3) {
                return { found: false, reachedEnd: false, steps, pos, reason: "stuck" };
            }
        } else {
            stuckCount = 0;
        }
        lastPos = pos;
    }

    return { found: false, reachedEnd: false, steps, pos: container.scrollLeft, reason: "max-steps" };
}
