import { ValueTag } from '@bilig/protocol';
import { addEngineCounter } from '../../perf/engine-counters.js';
import { findExactNumericApproximateMatchInRange, isLookupColumnOwner, sliceOffsetBounds, summarizeApproximateRange, } from './lookup-column-owner.js';
import { columnRegistryKey, compareApproximateNumeric, compareApproximateText, decodeValueTag, detectRepeatedUniformNumericStep, detectUniformNumericStep, findRepeatedUniformNumericApproximatePosition, findUniformNumericApproximatePosition, getColumnCacheKey, normalizeApproximateComparableValue, resolveSingleColumnBounds, supportsPreparedApproximateKind, } from './sorted-column-search-helpers.js';
export function createSortedColumnSearchService(args) {
    const emptyColumnVersions = new Uint32Array(0);
    const approximateColumnIndices = new Map();
    const cacheKeysByColumn = new Map();
    const readPreparedOwner = (prepared) => isLookupColumnOwner(prepared.internalOwner) ? prepared.internalOwner : undefined;
    const getCurrentColumnVersions = (sheetName, col) => {
        const sheet = args.state.workbook.getSheet(sheetName);
        const sheetColumnVersions = sheet?.columnVersions ?? emptyColumnVersions;
        return {
            columnVersion: sheetColumnVersions[col] ?? 0,
            structureVersion: sheet?.structureVersion ?? 0,
            sheetColumnVersions,
        };
    };
    const trackCacheKey = (sheetName, col, cacheKey) => {
        const registryKey = columnRegistryKey(sheetName, col);
        const existing = cacheKeysByColumn.get(registryKey);
        if (existing) {
            existing.add(cacheKey);
            return;
        }
        cacheKeysByColumn.set(registryKey, new Set([cacheKey]));
    };
    const ensureOwnerIndex = (sheetName, col) => {
        return args.columnIndexStore.getLookupColumnOwner({ sheetName, col });
    };
    const untrackCacheKey = (sheetName, col, cacheKey) => {
        const registryKey = columnRegistryKey(sheetName, col);
        const existing = cacheKeysByColumn.get(registryKey);
        if (!existing) {
            return;
        }
        existing.delete(cacheKey);
        if (existing.size === 0) {
            cacheKeysByColumn.delete(registryKey);
        }
    };
    const replaceColumnIndex = (cacheKey, entry) => {
        const existing = approximateColumnIndices.get(cacheKey);
        if (existing) {
            untrackCacheKey(existing.sheetName, existing.col, cacheKey);
            approximateColumnIndices.delete(cacheKey);
        }
        if (!entry) {
            return;
        }
        approximateColumnIndices.set(cacheKey, entry);
        trackCacheKey(entry.sheetName, entry.col, cacheKey);
    };
    const comparableAtOffset = (view, offset) => {
        const tag = decodeValueTag(view.readTagAt(offset));
        switch (tag) {
            case ValueTag.Empty:
                return { kind: 'empty' };
            case ValueTag.Number:
                return { kind: 'numeric', value: view.readNumberAt(offset) };
            case ValueTag.Boolean:
                return { kind: 'numeric', value: view.readNumberAt(offset) !== 0 ? 1 : 0 };
            case ValueTag.String:
                return {
                    kind: 'text',
                    value: args.runtimeColumnStore.normalizeStringId(view.readStringIdAt(offset)),
                };
            case ValueTag.Error:
            default:
                return { kind: 'invalid' };
        }
    };
    const buildApproximateColumnIndex = (sheetName, col, rowStart, rowEnd) => {
        if (args.state.counters) {
            addEngineCounter(args.state.counters, 'approxIndexBuilds');
        }
        const view = args.runtimeColumnStore.getColumnView({
            sheetName,
            rowStart,
            rowEnd,
            col,
        });
        const rawValues = [];
        let hasNumeric = false;
        let hasText = false;
        let hasInvalid = false;
        for (let offset = 0; offset < view.length; offset += 1) {
            const comparable = comparableAtOffset(view, offset);
            rawValues.push(comparable);
            hasNumeric ||= comparable.kind === 'numeric';
            hasText ||= comparable.kind === 'text';
            hasInvalid ||= comparable.kind === 'invalid';
        }
        if (hasInvalid || (hasNumeric && hasText)) {
            return {
                sheetName,
                rowStart,
                rowEnd,
                col,
                columnVersion: view.columnVersion,
                structureVersion: view.structureVersion,
                comparableKind: undefined,
                uniformStart: undefined,
                uniformStep: undefined,
                repeatedUniformStart: undefined,
                repeatedUniformStep: undefined,
                repeatedUniformRunLength: undefined,
                sortedAscending: false,
                sortedDescending: false,
                numericValues: undefined,
                textValues: undefined,
            };
        }
        if (hasText) {
            const textValues = rawValues.map((value) => (value.kind === 'text' ? value.value : ''));
            let sortedAscending = true;
            let sortedDescending = true;
            for (let index = 1; index < textValues.length; index += 1) {
                const comparison = compareApproximateText(textValues[index - 1], textValues[index]);
                if (comparison > 0) {
                    sortedAscending = false;
                }
                if (comparison < 0) {
                    sortedDescending = false;
                }
            }
            return {
                sheetName,
                rowStart,
                rowEnd,
                col,
                columnVersion: view.columnVersion,
                structureVersion: view.structureVersion,
                comparableKind: 'text',
                uniformStart: undefined,
                uniformStep: undefined,
                repeatedUniformStart: undefined,
                repeatedUniformStep: undefined,
                repeatedUniformRunLength: undefined,
                sortedAscending,
                sortedDescending,
                numericValues: undefined,
                textValues,
            };
        }
        const numericValues = Float64Array.from(rawValues, (value) => (value.kind === 'numeric' ? value.value : 0));
        let sortedAscending = true;
        let sortedDescending = true;
        for (let index = 1; index < numericValues.length; index += 1) {
            const comparison = compareApproximateNumeric(numericValues[index - 1], numericValues[index]);
            if (comparison > 0) {
                sortedAscending = false;
            }
            if (comparison < 0) {
                sortedDescending = false;
            }
        }
        const uniformNumericStep = detectUniformNumericStep(numericValues);
        const repeatedUniformNumericStep = uniformNumericStep === undefined ? detectRepeatedUniformNumericStep(numericValues) : undefined;
        return {
            sheetName,
            rowStart,
            rowEnd,
            col,
            columnVersion: view.columnVersion,
            structureVersion: view.structureVersion,
            comparableKind: 'numeric',
            uniformStart: uniformNumericStep?.start,
            uniformStep: uniformNumericStep?.step,
            repeatedUniformStart: repeatedUniformNumericStep?.start,
            repeatedUniformStep: repeatedUniformNumericStep?.step,
            repeatedUniformRunLength: repeatedUniformNumericStep?.runLength,
            sortedAscending,
            sortedDescending,
            numericValues,
            textValues: undefined,
        };
    };
    const ensureColumnIndex = (sheetName, col, rowStart, rowEnd) => {
        const cacheKey = getColumnCacheKey(sheetName, col, rowStart, rowEnd);
        const currentVersions = getCurrentColumnVersions(sheetName, col);
        let entry = approximateColumnIndices.get(cacheKey);
        if (!entry || entry.columnVersion !== currentVersions.columnVersion || entry.structureVersion !== currentVersions.structureVersion) {
            entry = buildApproximateColumnIndex(sheetName, col, rowStart, rowEnd);
            replaceColumnIndex(cacheKey, entry);
        }
        return entry;
    };
    const updateEntryLiteralWrite = (entry, row, oldValue, newValue, currentColumnVersion, currentStructureVersion) => {
        entry.columnVersion = currentColumnVersion;
        entry.structureVersion = currentStructureVersion;
        if (row < entry.rowStart || row > entry.rowEnd) {
            return true;
        }
        if (oldValue.kind !== newValue.kind) {
            return false;
        }
        if (oldValue.kind === 'invalid' || newValue.kind === 'invalid') {
            return false;
        }
        if (entry.comparableKind === undefined) {
            return false;
        }
        if ((entry.comparableKind === 'numeric' && newValue.kind !== 'numeric' && newValue.kind !== 'empty') ||
            (entry.comparableKind === 'text' && newValue.kind !== 'text' && newValue.kind !== 'empty')) {
            return false;
        }
        const offset = row - entry.rowStart;
        if (entry.comparableKind === 'numeric') {
            if (!entry.numericValues) {
                return false;
            }
            const nextNumeric = newValue.kind === 'numeric' ? newValue.value : 0;
            entry.numericValues[offset] = nextNumeric;
            entry.uniformStart = undefined;
            entry.uniformStep = undefined;
            entry.repeatedUniformStart = undefined;
            entry.repeatedUniformStep = undefined;
            entry.repeatedUniformRunLength = undefined;
            const previous = offset > 0 ? entry.numericValues[offset - 1] : undefined;
            const next = offset + 1 < entry.numericValues.length ? entry.numericValues[offset + 1] : undefined;
            if ((previous !== undefined && compareApproximateNumeric(previous, nextNumeric) > 0) ||
                (next !== undefined && compareApproximateNumeric(nextNumeric, next) > 0)) {
                entry.sortedAscending = false;
            }
            if ((previous !== undefined && compareApproximateNumeric(previous, nextNumeric) < 0) ||
                (next !== undefined && compareApproximateNumeric(nextNumeric, next) < 0)) {
                entry.sortedDescending = false;
            }
            return true;
        }
        if (!entry.textValues) {
            return false;
        }
        const nextText = newValue.kind === 'text' ? newValue.value : '';
        entry.textValues[offset] = nextText;
        const previous = offset > 0 ? entry.textValues[offset - 1] : undefined;
        const next = offset + 1 < entry.textValues.length ? entry.textValues[offset + 1] : undefined;
        if ((previous !== undefined && compareApproximateText(previous, nextText) > 0) ||
            (next !== undefined && compareApproximateText(nextText, next) > 0)) {
            entry.sortedAscending = false;
        }
        if ((previous !== undefined && compareApproximateText(previous, nextText) < 0) ||
            (next !== undefined && compareApproximateText(nextText, next) < 0)) {
            entry.sortedDescending = false;
        }
        return true;
    };
    const prepareVectorLookup = (request) => {
        const owner = ensureOwnerIndex(request.sheetName, request.col);
        if (owner && request.rowStart >= owner.rowStart && request.rowEnd <= owner.rowEnd) {
            const summary = summarizeApproximateRange(owner, request.rowStart, request.rowEnd);
            return {
                sheetName: request.sheetName,
                rowStart: request.rowStart,
                rowEnd: request.rowEnd,
                col: request.col,
                length: request.rowEnd - request.rowStart + 1,
                columnVersion: owner.columnVersion,
                structureVersion: owner.structureVersion,
                sheetColumnVersions: owner.sheetColumnVersions,
                comparableKind: summary?.comparableKind,
                uniformStart: summary?.uniformStart,
                uniformStep: summary?.uniformStep,
                repeatedUniformStart: summary?.repeatedUniformStart,
                repeatedUniformStep: summary?.repeatedUniformStep,
                repeatedUniformRunLength: summary?.repeatedUniformRunLength,
                sortedAscending: summary?.sortedAscending ?? false,
                sortedDescending: summary?.sortedDescending ?? false,
                numericValues: undefined,
                textValues: undefined,
                internalOwner: owner,
            };
        }
        const entry = ensureColumnIndex(request.sheetName, request.col, request.rowStart, request.rowEnd);
        return {
            sheetName: request.sheetName,
            rowStart: request.rowStart,
            rowEnd: request.rowEnd,
            col: request.col,
            length: request.rowEnd - request.rowStart + 1,
            columnVersion: entry.columnVersion,
            structureVersion: entry.structureVersion,
            sheetColumnVersions: getCurrentColumnVersions(request.sheetName, request.col).sheetColumnVersions,
            comparableKind: entry.comparableKind,
            uniformStart: entry.uniformStart,
            uniformStep: entry.uniformStep,
            repeatedUniformStart: entry.repeatedUniformStart,
            repeatedUniformStep: entry.repeatedUniformStep,
            repeatedUniformRunLength: entry.repeatedUniformRunLength,
            sortedAscending: entry.sortedAscending,
            sortedDescending: entry.sortedDescending,
            numericValues: entry.numericValues,
            textValues: entry.textValues,
            internalOwner: undefined,
        };
    };
    const refreshPreparedVectorLookup = (prepared) => {
        const owner = readPreparedOwner(prepared);
        if (owner) {
            const currentVersions = getCurrentColumnVersions(prepared.sheetName, prepared.col);
            if (currentVersions.columnVersion === prepared.columnVersion && currentVersions.structureVersion === prepared.structureVersion) {
                return prepared;
            }
            const refreshedOwner = ensureOwnerIndex(prepared.sheetName, prepared.col);
            if (refreshedOwner && prepared.rowStart >= refreshedOwner.rowStart && prepared.rowEnd <= refreshedOwner.rowEnd) {
                const summary = summarizeApproximateRange(refreshedOwner, prepared.rowStart, prepared.rowEnd);
                prepared.length = prepared.rowEnd - prepared.rowStart + 1;
                prepared.columnVersion = refreshedOwner.columnVersion;
                prepared.structureVersion = refreshedOwner.structureVersion;
                prepared.sheetColumnVersions = refreshedOwner.sheetColumnVersions;
                prepared.comparableKind = summary?.comparableKind;
                prepared.uniformStart = summary?.uniformStart;
                prepared.uniformStep = summary?.uniformStep;
                prepared.repeatedUniformStart = summary?.repeatedUniformStart;
                prepared.repeatedUniformStep = summary?.repeatedUniformStep;
                prepared.repeatedUniformRunLength = summary?.repeatedUniformRunLength;
                prepared.sortedAscending = summary?.sortedAscending ?? false;
                prepared.sortedDescending = summary?.sortedDescending ?? false;
                prepared.internalOwner = refreshedOwner;
                return prepared;
            }
        }
        const currentVersions = getCurrentColumnVersions(prepared.sheetName, prepared.col);
        if (currentVersions.columnVersion === prepared.columnVersion && currentVersions.structureVersion === prepared.structureVersion) {
            return prepared;
        }
        const refreshed = prepareVectorLookup(prepared);
        prepared.length = refreshed.length;
        prepared.columnVersion = refreshed.columnVersion;
        prepared.structureVersion = refreshed.structureVersion;
        prepared.sheetColumnVersions = refreshed.sheetColumnVersions;
        prepared.comparableKind = refreshed.comparableKind;
        prepared.uniformStart = refreshed.uniformStart;
        prepared.uniformStep = refreshed.uniformStep;
        prepared.repeatedUniformStart = refreshed.repeatedUniformStart;
        prepared.repeatedUniformStep = refreshed.repeatedUniformStep;
        prepared.repeatedUniformRunLength = refreshed.repeatedUniformRunLength;
        prepared.sortedAscending = refreshed.sortedAscending;
        prepared.sortedDescending = refreshed.sortedDescending;
        prepared.numericValues = refreshed.numericValues;
        prepared.textValues = refreshed.textValues;
        prepared.internalOwner = refreshed.internalOwner;
        return prepared;
    };
    const findPreparedVectorMatch = (request) => {
        const prepared = refreshPreparedVectorLookup(request.prepared);
        const owner = readPreparedOwner(prepared);
        if (owner) {
            const bounds = sliceOffsetBounds(owner, prepared.rowStart, prepared.rowEnd);
            if (!bounds) {
                return { handled: false };
            }
            if (request.lookupValue.tag === ValueTag.Empty) {
                if (supportsPreparedApproximateKind(prepared, 'numeric', request.matchMode)) {
                    const uniformResult = findUniformNumericApproximatePosition({
                        lookupValue: 0,
                        length: bounds.end - bounds.start + 1,
                        matchMode: request.matchMode,
                        uniformStart: prepared.uniformStart,
                        uniformStep: prepared.uniformStep,
                    });
                    if (uniformResult.handled) {
                        return uniformResult;
                    }
                    const repeatedUniformResult = findRepeatedUniformNumericApproximatePosition({
                        lookupValue: 0,
                        length: bounds.end - bounds.start + 1,
                        matchMode: request.matchMode,
                        repeatedUniformStart: prepared.repeatedUniformStart,
                        repeatedUniformStep: prepared.repeatedUniformStep,
                        repeatedUniformRunLength: prepared.repeatedUniformRunLength,
                    });
                    if (repeatedUniformResult.handled) {
                        return repeatedUniformResult;
                    }
                    const exactNumericRow = findExactNumericApproximateMatchInRange(owner, 0, prepared.rowStart, prepared.rowEnd);
                    if (exactNumericRow !== undefined) {
                        return { handled: true, position: exactNumericRow - prepared.rowStart + 1 };
                    }
                    let low = bounds.start;
                    let high = bounds.end;
                    let best = -1;
                    while (low <= high) {
                        const mid = (low + high) >> 1;
                        const comparison = compareApproximateNumeric(owner.numericValues[mid], 0);
                        if (request.matchMode === 1) {
                            if (comparison <= 0) {
                                best = mid;
                                low = mid + 1;
                            }
                            else {
                                high = mid - 1;
                            }
                        }
                        else if (comparison >= 0) {
                            best = mid;
                            low = mid + 1;
                        }
                        else {
                            high = mid - 1;
                        }
                    }
                    return { handled: true, position: best === -1 ? undefined : best - bounds.start + 1 };
                }
                if (!supportsPreparedApproximateKind(prepared, 'text', request.matchMode)) {
                    return { handled: false };
                }
                let low = bounds.start;
                let high = bounds.end;
                let best = -1;
                while (low <= high) {
                    const mid = (low + high) >> 1;
                    const comparison = compareApproximateText(owner.textValues[mid] ?? '', '');
                    if (request.matchMode === 1) {
                        if (comparison <= 0) {
                            best = mid;
                            low = mid + 1;
                        }
                        else {
                            high = mid - 1;
                        }
                    }
                    else if (comparison >= 0) {
                        best = mid;
                        low = mid + 1;
                    }
                    else {
                        high = mid - 1;
                    }
                }
                return { handled: true, position: best === -1 ? undefined : best - bounds.start + 1 };
            }
            if (request.lookupValue.tag === ValueTag.Number || request.lookupValue.tag === ValueTag.Boolean) {
                if (!supportsPreparedApproximateKind(prepared, 'numeric', request.matchMode)) {
                    return { handled: false };
                }
                let lookupValue;
                switch (request.lookupValue.tag) {
                    case ValueTag.Number:
                        lookupValue = Object.is(request.lookupValue.value, -0) ? 0 : request.lookupValue.value;
                        break;
                    case ValueTag.Boolean:
                        lookupValue = request.lookupValue.value ? 1 : 0;
                        break;
                    default:
                        return { handled: false };
                }
                const uniformResult = findUniformNumericApproximatePosition({
                    lookupValue,
                    length: bounds.end - bounds.start + 1,
                    matchMode: request.matchMode,
                    uniformStart: prepared.uniformStart,
                    uniformStep: prepared.uniformStep,
                });
                if (uniformResult.handled) {
                    return uniformResult;
                }
                const repeatedUniformResult = findRepeatedUniformNumericApproximatePosition({
                    lookupValue,
                    length: bounds.end - bounds.start + 1,
                    matchMode: request.matchMode,
                    repeatedUniformStart: prepared.repeatedUniformStart,
                    repeatedUniformStep: prepared.repeatedUniformStep,
                    repeatedUniformRunLength: prepared.repeatedUniformRunLength,
                });
                if (repeatedUniformResult.handled) {
                    return repeatedUniformResult;
                }
                const exactNumericRow = findExactNumericApproximateMatchInRange(owner, lookupValue, prepared.rowStart, prepared.rowEnd);
                if (exactNumericRow !== undefined) {
                    return { handled: true, position: exactNumericRow - prepared.rowStart + 1 };
                }
                let low = bounds.start;
                let high = bounds.end;
                let best = -1;
                while (low <= high) {
                    const mid = (low + high) >> 1;
                    const comparison = compareApproximateNumeric(owner.numericValues[mid], lookupValue);
                    if (request.matchMode === 1) {
                        if (comparison <= 0) {
                            best = mid;
                            low = mid + 1;
                        }
                        else {
                            high = mid - 1;
                        }
                    }
                    else if (comparison >= 0) {
                        best = mid;
                        low = mid + 1;
                    }
                    else {
                        high = mid - 1;
                    }
                }
                return { handled: true, position: best === -1 ? undefined : best - bounds.start + 1 };
            }
            if (request.lookupValue.tag === ValueTag.String) {
                if (!supportsPreparedApproximateKind(prepared, 'text', request.matchMode)) {
                    return { handled: false };
                }
                const lookupValue = args.runtimeColumnStore.normalizeLookupText(request.lookupValue);
                let low = bounds.start;
                let high = bounds.end;
                let best = -1;
                while (low <= high) {
                    const mid = (low + high) >> 1;
                    const comparison = compareApproximateText(owner.textValues[mid] ?? '', lookupValue);
                    if (request.matchMode === 1) {
                        if (comparison <= 0) {
                            best = mid;
                            low = mid + 1;
                        }
                        else {
                            high = mid - 1;
                        }
                    }
                    else if (comparison >= 0) {
                        best = mid;
                        low = mid + 1;
                    }
                    else {
                        high = mid - 1;
                    }
                }
                return { handled: true, position: best === -1 ? undefined : best - bounds.start + 1 };
            }
            return { handled: false };
        }
        if (prepared.comparableKind === undefined) {
            return { handled: false };
        }
        if (request.matchMode === 1 && !prepared.sortedAscending) {
            return { handled: false };
        }
        if (request.matchMode === -1 && !prepared.sortedDescending) {
            return { handled: false };
        }
        if (prepared.comparableKind === 'numeric') {
            let lookupValue;
            switch (request.lookupValue.tag) {
                case ValueTag.Empty:
                    lookupValue = 0;
                    break;
                case ValueTag.Number:
                    lookupValue = Object.is(request.lookupValue.value, -0) ? 0 : request.lookupValue.value;
                    break;
                case ValueTag.Boolean:
                    lookupValue = request.lookupValue.value ? 1 : 0;
                    break;
                case ValueTag.Error:
                case ValueTag.String:
                    return { handled: false };
            }
            const values = prepared.numericValues;
            if (!values) {
                return { handled: false };
            }
            const uniformResult = findUniformNumericApproximatePosition({
                lookupValue,
                length: values.length,
                matchMode: request.matchMode,
                uniformStart: prepared.uniformStart,
                uniformStep: prepared.uniformStep,
            });
            if (uniformResult.handled) {
                return uniformResult;
            }
            const repeatedUniformResult = findRepeatedUniformNumericApproximatePosition({
                lookupValue,
                length: values.length,
                matchMode: request.matchMode,
                repeatedUniformStart: prepared.repeatedUniformStart,
                repeatedUniformStep: prepared.repeatedUniformStep,
                repeatedUniformRunLength: prepared.repeatedUniformRunLength,
            });
            if (repeatedUniformResult.handled) {
                return repeatedUniformResult;
            }
            let low = 0;
            let high = values.length - 1;
            let best = -1;
            while (low <= high) {
                const mid = (low + high) >> 1;
                const comparison = compareApproximateNumeric(values[mid], lookupValue);
                if (request.matchMode === 1) {
                    if (comparison <= 0) {
                        best = mid;
                        low = mid + 1;
                    }
                    else {
                        high = mid - 1;
                    }
                }
                else if (comparison >= 0) {
                    best = mid;
                    low = mid + 1;
                }
                else {
                    high = mid - 1;
                }
            }
            return { handled: true, position: best === -1 ? undefined : best + 1 };
        }
        let lookupValue;
        switch (request.lookupValue.tag) {
            case ValueTag.Empty:
                lookupValue = '';
                break;
            case ValueTag.String:
                lookupValue = args.runtimeColumnStore.normalizeLookupText(request.lookupValue);
                break;
            case ValueTag.Error:
            case ValueTag.Number:
            case ValueTag.Boolean:
                return { handled: false };
        }
        const values = prepared.textValues;
        if (!values) {
            return { handled: false };
        }
        let low = 0;
        let high = values.length - 1;
        let best = -1;
        while (low <= high) {
            const mid = (low + high) >> 1;
            const comparison = compareApproximateText(values[mid], lookupValue);
            if (request.matchMode === 1) {
                if (comparison <= 0) {
                    best = mid;
                    low = mid + 1;
                }
                else {
                    high = mid - 1;
                }
            }
            else if (comparison >= 0) {
                best = mid;
                low = mid + 1;
            }
            else {
                high = mid - 1;
            }
        }
        return { handled: true, position: best === -1 ? undefined : best + 1 };
    };
    return {
        primeColumnIndex(request) {
            const owner = ensureOwnerIndex(request.sheetName, request.col);
            if (owner && request.rowStart >= owner.rowStart && request.rowEnd <= owner.rowEnd) {
                return;
            }
            ensureColumnIndex(request.sheetName, request.col, request.rowStart, request.rowEnd);
        },
        prepareVectorLookup(request) {
            return prepareVectorLookup(request);
        },
        findPreparedVectorMatch(request) {
            return findPreparedVectorMatch(request);
        },
        findVectorMatch(request) {
            const bounds = resolveSingleColumnBounds(request);
            if (!bounds) {
                return { handled: false };
            }
            const prepared = prepareVectorLookup({
                sheetName: request.sheetName,
                rowStart: bounds.rowStart,
                rowEnd: bounds.rowEnd,
                col: bounds.col,
            });
            return findPreparedVectorMatch({
                lookupValue: request.lookupValue,
                prepared,
                matchMode: request.matchMode,
            });
        },
        /* c8 ignore start */
        invalidateColumn(request) {
            args.columnIndexStore.invalidateColumn({ sheetName: request.sheetName, col: request.col });
            const cacheKeys = cacheKeysByColumn.get(columnRegistryKey(request.sheetName, request.col));
            if (!cacheKeys) {
                return;
            }
            for (const cacheKey of cacheKeys) {
                replaceColumnIndex(cacheKey, undefined);
            }
        },
        recordLiteralWrite(request) {
            const registryKey = columnRegistryKey(request.sheetName, request.col);
            args.columnIndexStore.recordLiteralWrite(request);
            const cacheKeys = cacheKeysByColumn.get(registryKey);
            if (!cacheKeys || cacheKeys.size === 0) {
                return;
            }
            const currentVersions = getCurrentColumnVersions(request.sheetName, request.col);
            const oldComparable = normalizeApproximateComparableValue(request.oldValue, (id) => args.state.strings.get(id), request.oldStringId);
            const newComparable = normalizeApproximateComparableValue(request.newValue, (id) => args.state.strings.get(id), request.newStringId);
            for (const cacheKey of cacheKeys) {
                const entry = approximateColumnIndices.get(cacheKey);
                if (!entry) {
                    continue;
                }
                if (entry.structureVersion !== currentVersions.structureVersion) {
                    replaceColumnIndex(cacheKey, undefined);
                    continue;
                }
                if (!updateEntryLiteralWrite(entry, request.row, oldComparable, newComparable, currentVersions.columnVersion, currentVersions.structureVersion)) {
                    replaceColumnIndex(cacheKey, undefined);
                }
            }
        },
        /* c8 ignore stop */
    };
}
//# sourceMappingURL=sorted-column-search-service.js.map