import Fuse from "fuse.js";

const FUZZY_SEARCH_OPTIONS = {
    includeMatches: true,
    threshold: 0.35,
    ignoreLocation: true,
    minMatchCharLength: 1,
    keys: [
        { name: "title", weight: 0.7 },
        { name: "uri", weight: 0.3 },
    ],
};

function mergeRanges(ranges) {
    if (!ranges.length) {
        return [];
    }

    const sorted = [...ranges].sort((a, b) => a[0] - b[0]);
    const merged = [sorted[0]];

    for (let i = 1; i < sorted.length; i += 1) {
        const [start, end] = sorted[i];
        const last = merged[merged.length - 1];

        if (start <= last[1] + 1) {
            last[1] = Math.max(last[1], end);
            continue;
        }

        merged.push([start, end]);
    }

    return merged;
}

function buildHighlights(matches = []) {
    const highlights = {
        title: [],
        uri: [],
    };

    matches.forEach((match) => {
        const key = String(match?.key || "").split(".").pop();
        if ((key !== "title" && key !== "uri") || !Array.isArray(match.indices)) {
            return;
        }

        highlights[key].push(...match.indices);
    });

    const title = mergeRanges(highlights.title);
    const uri = mergeRanges(highlights.uri);

    if (!title.length && !uri.length) {
        return null;
    }

    return { title, uri };
}

export function fuzzySearchPages(pages, searchTerm) {
    const sourcePages = Array.isArray(pages) ? pages : [];
    const term = String(searchTerm || "").trim();

    if (!term) {
        return sourcePages.map((page) => ({
            page,
            highlights: null,
        }));
    }

    const fuse = new Fuse(sourcePages, FUZZY_SEARCH_OPTIONS);

    return fuse.search(term).map((result) => ({
        page: result.item,
        highlights: buildHighlights(result.matches),
    }));
}
