import { ValueTag } from '@bilig/protocol';
import { exactLookupNumberKey, normalizeExactLookupNumber } from '@bilig/formula';
const MAX_COLUMN_OWNER_SPAN = 1_048_576;
const EMPTY_KIND = 0;
const NUMERIC_KIND = 1;
const BOOLEAN_KIND = 2;
const TEXT_KIND = 3;
const INVALID_KIND = 4;
function decodeComparableKindCode(raw) {
    switch (raw) {
        case undefined:
            return EMPTY_KIND;
        case EMPTY_KIND:
            return EMPTY_KIND;
        case NUMERIC_KIND:
            return NUMERIC_KIND;
        case BOOLEAN_KIND:
            return BOOLEAN_KIND;
        case TEXT_KIND:
            return TEXT_KIND;
        case INVALID_KIND:
            return INVALID_KIND;
        default:
            return EMPTY_KIND;
    }
}
export function isLookupColumnOwner(value) {
    return (value !== null &&
        typeof value === 'object' &&
        'sheetName' in value &&
        typeof value.sheetName === 'string' &&
        'col' in value &&
        typeof value.col === 'number' &&
        'rowStart' in value &&
        typeof value.rowStart === 'number' &&
        'rowEnd' in value &&
        typeof value.rowEnd === 'number' &&
        'length' in value &&
        typeof value.length === 'number' &&
        'kindCodes' in value &&
        value.kindCodes instanceof Uint8Array &&
        'numericValues' in value &&
        value.numericValues instanceof Float64Array &&
        'textValues' in value &&
        Array.isArray(value.textValues) &&
        'rowLists' in value &&
        value.rowLists instanceof Map);
}
function decodeValueTag(rawTag) {
    if (rawTag === undefined) {
        return ValueTag.Empty;
    }
    switch (rawTag) {
        case 1:
            return ValueTag.Number;
        case 2:
            return ValueTag.Boolean;
        case 3:
            return ValueTag.String;
        case 4:
            return ValueTag.Error;
        case 0:
        default:
            return ValueTag.Empty;
    }
}
function kindCodeForValue(value) {
    switch (value.tag) {
        case ValueTag.Empty:
            return EMPTY_KIND;
        case ValueTag.Number:
            return NUMERIC_KIND;
        case ValueTag.Boolean:
            return BOOLEAN_KIND;
        case ValueTag.String:
            return TEXT_KIND;
        case ValueTag.Error:
            return INVALID_KIND;
    }
}
function numericValueForValue(value) {
    switch (value.tag) {
        case ValueTag.Empty:
            return 0;
        case ValueTag.Number:
            return normalizeExactLookupNumber(value.value);
        case ValueTag.Boolean:
            return value.value ? 1 : 0;
        case ValueTag.String:
        case ValueTag.Error:
            return 0;
    }
}
function textValueForValue(value, normalizeStringId, stringId = 0) {
    if (value.tag === ValueTag.String) {
        return (stringId !== 0 ? normalizeStringId(stringId) : value.value).toUpperCase();
    }
    return '';
}
function exactLookupKeyForValue(value, normalizeStringId, stringId = 0) {
    switch (value.tag) {
        case ValueTag.Empty:
            return 'e:';
        case ValueTag.Number:
            return exactLookupNumberKey(value.value);
        case ValueTag.Boolean:
            return value.value ? 'b:1' : 'b:0';
        case ValueTag.String:
            return `s:${(stringId !== 0 ? normalizeStringId(stringId) : value.value).toUpperCase()}`;
        case ValueTag.Error:
            return undefined;
    }
}
function exactLookupKeyAt(owner, offset) {
    switch (decodeComparableKindCode(owner.kindCodes[offset])) {
        case EMPTY_KIND:
            return 'e:';
        case NUMERIC_KIND:
            return exactLookupNumberKey(owner.numericValues[offset] ?? 0);
        case BOOLEAN_KIND:
            return (owner.numericValues[offset] ?? 0) !== 0 ? 'b:1' : 'b:0';
        case TEXT_KIND:
            return `s:${owner.textValues[offset] ?? ''}`;
        case INVALID_KIND:
        default:
            return 'x:';
    }
}
function insertRowSorted(rows, row) {
    let low = 0;
    let high = rows.length;
    while (low < high) {
        const mid = (low + high) >> 1;
        if (rows[mid] < row) {
            low = mid + 1;
        }
        else {
            high = mid;
        }
    }
    rows.splice(low, 0, row);
}
function lowerBound(rows, target) {
    let low = 0;
    let high = rows.length;
    while (low < high) {
        const mid = (low + high) >> 1;
        if (rows[mid] < target) {
            low = mid + 1;
        }
        else {
            high = mid;
        }
    }
    return low;
}
function upperBound(rows, target) {
    let low = 0;
    let high = rows.length;
    while (low < high) {
        const mid = (low + high) >> 1;
        if (rows[mid] <= target) {
            low = mid + 1;
        }
        else {
            high = mid;
        }
    }
    return low;
}
function arrayValueAt(values, index) {
    return index >= 0 && index < values.length ? values[index] : undefined;
}
function exactLowerBound(rows, target) {
    let low = 0;
    let high = rows.length;
    while (low < high) {
        const mid = (low + high) >> 1;
        if ((rows[mid] ?? 0) < target) {
            low = mid + 1;
        }
        else {
            high = mid;
        }
    }
    return low;
}
function hasOffsetInRange(offsets, start, end) {
    if (!offsets || offsets.length === 0 || start > end) {
        return false;
    }
    const index = exactLowerBound(offsets, start);
    return index < offsets.length && (offsets[index] ?? 0) <= end;
}
function withOffsetMembership(offsets, target, present) {
    const source = offsets ?? new Uint32Array(0);
    const index = exactLowerBound(source, target);
    const exists = index < source.length && (source[index] ?? 0) === target;
    if (exists === present) {
        return source;
    }
    if (present) {
        const result = new Uint32Array(source.length + 1);
        result.set(source.subarray(0, index), 0);
        result[index] = target;
        result.set(source.subarray(index), index + 1);
        return result;
    }
    const result = new Uint32Array(source.length - 1);
    result.set(source.subarray(0, index), 0);
    result.set(source.subarray(index + 1), index);
    return result;
}
function isNumericApproximateIncompatibleKind(kind) {
    return kind === TEXT_KIND || kind === INVALID_KIND;
}
function isTextApproximateIncompatibleKind(kind) {
    return kind === NUMERIC_KIND || kind === BOOLEAN_KIND || kind === INVALID_KIND;
}
function initializeApproximateLookupSummaries(owner) {
    const numericAscendingBreaks = [];
    const numericDescendingBreaks = [];
    const numericUniformBreakOffsets = [];
    const textAscendingBreaks = [];
    const textDescendingBreaks = [];
    const incompatibleNumericOffsets = [];
    const incompatibleTextOffsets = [];
    const exactNumericIncompatibleOffsets = [];
    const exactTextIncompatibleOffsets = [];
    for (let offset = 0; offset < owner.length; offset += 1) {
        const kind = decodeComparableKindCode(owner.kindCodes[offset]);
        if (isNumericApproximateIncompatibleKind(kind)) {
            incompatibleNumericOffsets.push(offset);
        }
        if (isTextApproximateIncompatibleKind(kind)) {
            incompatibleTextOffsets.push(offset);
        }
        if (kind !== NUMERIC_KIND) {
            exactNumericIncompatibleOffsets.push(offset);
        }
        if (kind !== TEXT_KIND) {
            exactTextIncompatibleOffsets.push(offset);
        }
        if (offset === 0) {
            continue;
        }
        if (owner.numericValues[offset - 1] > owner.numericValues[offset]) {
            numericAscendingBreaks.push(offset);
        }
        if (owner.numericValues[offset - 1] < owner.numericValues[offset]) {
            numericDescendingBreaks.push(offset);
        }
        if (offset >= 2 &&
            owner.numericValues[offset - 2] - owner.numericValues[offset - 1] !==
                owner.numericValues[offset - 1] - owner.numericValues[offset]) {
            numericUniformBreakOffsets.push(offset);
        }
        if ((owner.textValues[offset - 1] ?? '') > (owner.textValues[offset] ?? '')) {
            textAscendingBreaks.push(offset);
        }
        if ((owner.textValues[offset - 1] ?? '') < (owner.textValues[offset] ?? '')) {
            textDescendingBreaks.push(offset);
        }
    }
    owner.incompatibleNumericOffsets = Uint32Array.from(incompatibleNumericOffsets);
    owner.incompatibleTextOffsets = Uint32Array.from(incompatibleTextOffsets);
    owner.exactNumericIncompatibleOffsets = Uint32Array.from(exactNumericIncompatibleOffsets);
    owner.exactTextIncompatibleOffsets = Uint32Array.from(exactTextIncompatibleOffsets);
    owner.sortedNumericAscendingBreaks = Uint32Array.from(numericAscendingBreaks);
    owner.sortedNumericDescendingBreaks = Uint32Array.from(numericDescendingBreaks);
    owner.numericUniformBreakOffsets = Uint32Array.from(numericUniformBreakOffsets);
    owner.sortedTextAscendingBreaks = Uint32Array.from(textAscendingBreaks);
    owner.sortedTextDescendingBreaks = Uint32Array.from(textDescendingBreaks);
    owner.summariesDirty = false;
}
function refreshExactLookupCompatibility(owner, offset) {
    const kind = decodeComparableKindCode(owner.kindCodes[offset]);
    owner.exactNumericIncompatibleOffsets = withOffsetMembership(owner.exactNumericIncompatibleOffsets, offset, kind !== NUMERIC_KIND);
    owner.exactTextIncompatibleOffsets = withOffsetMembership(owner.exactTextIncompatibleOffsets, offset, kind !== TEXT_KIND);
}
function refreshApproximateLookupCompatibility(owner, offset) {
    const kind = decodeComparableKindCode(owner.kindCodes[offset]);
    owner.incompatibleNumericOffsets = withOffsetMembership(owner.incompatibleNumericOffsets, offset, isNumericApproximateIncompatibleKind(kind));
    owner.incompatibleTextOffsets = withOffsetMembership(owner.incompatibleTextOffsets, offset, isTextApproximateIncompatibleKind(kind));
    refreshExactLookupCompatibility(owner, offset);
}
function refreshApproximateLookupBreaks(owner, offset) {
    if (offset <= 0 || offset >= owner.length) {
        return;
    }
    owner.sortedNumericAscendingBreaks = withOffsetMembership(owner.sortedNumericAscendingBreaks, offset, owner.numericValues[offset - 1] > owner.numericValues[offset]);
    owner.sortedNumericDescendingBreaks = withOffsetMembership(owner.sortedNumericDescendingBreaks, offset, owner.numericValues[offset - 1] < owner.numericValues[offset]);
    owner.sortedTextAscendingBreaks = withOffsetMembership(owner.sortedTextAscendingBreaks, offset, (owner.textValues[offset - 1] ?? '') > (owner.textValues[offset] ?? ''));
    owner.sortedTextDescendingBreaks = withOffsetMembership(owner.sortedTextDescendingBreaks, offset, (owner.textValues[offset - 1] ?? '') < (owner.textValues[offset] ?? ''));
}
function refreshNumericUniformBreak(owner, offset) {
    if (offset <= 1 || offset >= owner.length) {
        return;
    }
    owner.numericUniformBreakOffsets = withOffsetMembership(owner.numericUniformBreakOffsets, offset, owner.numericValues[offset - 2] - owner.numericValues[offset - 1] !== owner.numericValues[offset - 1] - owner.numericValues[offset]);
}
function removeOwnerKeyRow(owner, key, row) {
    const rows = owner.rowLists.get(key);
    if (rows) {
        const rowIndex = lowerBound(rows, row);
        if (arrayValueAt(rows, rowIndex) !== row) {
            return false;
        }
        rows.splice(rowIndex, 1);
        if (rows.length === 0) {
            owner.rowLists.delete(key);
            owner.firstPositions.delete(key);
            owner.lastPositions.delete(key);
            return true;
        }
        if (rows.length === 1) {
            const onlyRow = rows[0];
            owner.rowLists.delete(key);
            owner.firstPositions.set(key, onlyRow);
            owner.lastPositions.set(key, onlyRow);
            return true;
        }
        owner.firstPositions.set(key, rows[0]);
        owner.lastPositions.set(key, rows[rows.length - 1]);
        return true;
    }
    const firstRow = owner.firstPositions.get(key);
    const lastRow = owner.lastPositions.get(key);
    if (firstRow === undefined || lastRow === undefined || firstRow !== row || lastRow !== row) {
        return false;
    }
    owner.firstPositions.delete(key);
    owner.lastPositions.delete(key);
    return true;
}
function insertOwnerKeyRow(owner, key, row) {
    const rows = owner.rowLists.get(key);
    if (rows) {
        insertRowSorted(rows, row);
        owner.firstPositions.set(key, rows[0]);
        owner.lastPositions.set(key, rows[rows.length - 1]);
        return;
    }
    const firstRow = owner.firstPositions.get(key);
    if (firstRow !== undefined) {
        const nextRows = firstRow < row ? [firstRow, row] : [row, firstRow];
        owner.rowLists.set(key, nextRows);
        owner.firstPositions.set(key, nextRows[0]);
        owner.lastPositions.set(key, nextRows[nextRows.length - 1]);
        return;
    }
    owner.firstPositions.set(key, row);
    owner.lastPositions.set(key, row);
}
function ownerKeyContainsRow(owner, key, row) {
    const rows = owner.rowLists.get(key);
    if (rows) {
        const index = lowerBound(rows, row);
        return arrayValueAt(rows, index) === row;
    }
    return owner.firstPositions.get(key) === row && owner.lastPositions.get(key) === row;
}
function ownerStoredComparableMatches(owner, offset, kind, numericValue, textValue) {
    if (decodeComparableKindCode(owner.kindCodes[offset]) !== kind) {
        return false;
    }
    switch (kind) {
        case NUMERIC_KIND:
        case BOOLEAN_KIND:
            return Object.is(owner.numericValues[offset] ?? 0, numericValue) || (owner.numericValues[offset] ?? 0) === numericValue;
        case TEXT_KIND:
            return (owner.textValues[offset] ?? '') === textValue;
        case EMPTY_KIND:
        case INVALID_KIND:
            return true;
    }
}
function detectUniformNumericStepInOwner(owner, start, end) {
    ensureExactLookupSummaries(owner);
    if (end - start < 1) {
        return undefined;
    }
    const first = owner.numericValues[start];
    const step = owner.numericValues[start + 1] - first;
    if (!Number.isFinite(step) || step === 0) {
        return undefined;
    }
    if (hasOffsetInRange(owner.numericUniformBreakOffsets, start + 2, end)) {
        return undefined;
    }
    return { start: first, step };
}
function detectRepeatedUniformNumericStepInOwner(owner, start, end) {
    const length = end - start + 1;
    if (length < 4) {
        return undefined;
    }
    const first = owner.numericValues[start];
    let runLength = 1;
    while (start + runLength <= end && owner.numericValues[start + runLength] === first) {
        runLength += 1;
    }
    if (runLength <= 1 || runLength >= length) {
        return undefined;
    }
    const step = owner.numericValues[start + runLength] - first;
    if (!Number.isFinite(step) || step === 0) {
        return undefined;
    }
    for (let offset = start; offset <= end; offset += 1) {
        const group = Math.floor((offset - start) / runLength);
        if (owner.numericValues[offset] !== first + step * group) {
            return undefined;
        }
    }
    return { start: first, step, runLength };
}
export function findExactMatchInRange(owner, key, rowStart, rowEnd, searchMode) {
    const rows = owner.rowLists.get(key);
    if (rows && rows.length > 0) {
        if (searchMode === 1) {
            const index = lowerBound(rows, rowStart);
            const row = rows[index];
            return row !== undefined && row <= rowEnd ? row : undefined;
        }
        const index = upperBound(rows, rowEnd) - 1;
        const row = rows[index];
        return row !== undefined && row >= rowStart ? row : undefined;
    }
    const row = searchMode === 1 ? owner.firstPositions.get(key) : owner.lastPositions.get(key);
    return row !== undefined && row >= rowStart && row <= rowEnd ? row : undefined;
}
export function findExactNumericApproximateMatchInRange(owner, lookupValue, rowStart, rowEnd) {
    if (!Number.isFinite(lookupValue)) {
        return undefined;
    }
    ensureExactLookupSummaries(owner);
    const bounds = sliceOffsetBounds(owner, rowStart, rowEnd);
    if (!bounds || hasOffsetInRange(owner.exactNumericIncompatibleOffsets, bounds.start, bounds.end)) {
        return undefined;
    }
    return findExactMatchInRange(owner, exactLookupNumberKey(lookupValue), rowStart, rowEnd, -1);
}
export function buildLookupColumnOwner(args) {
    let minRow = Number.POSITIVE_INFINITY;
    let maxRow = Number.NEGATIVE_INFINITY;
    args.owner.pages.forEach((page) => {
        for (let localRow = 0; localRow < page.tags.length; localRow += 1) {
            if (decodeValueTag(page.tags[localRow]) === ValueTag.Empty) {
                continue;
            }
            const row = page.rowStart + localRow;
            minRow = Math.min(minRow, row);
            maxRow = Math.max(maxRow, row);
        }
    });
    if (!Number.isFinite(minRow) || !Number.isFinite(maxRow)) {
        return undefined;
    }
    const length = maxRow - minRow + 1;
    if (length > MAX_COLUMN_OWNER_SPAN) {
        return undefined;
    }
    const kindCodes = new Uint8Array(length);
    const numericValues = new Float64Array(length);
    const textValues = [];
    args.owner.pages.forEach((page) => {
        for (let localRow = 0; localRow < page.tags.length; localRow += 1) {
            const tag = decodeValueTag(page.tags[localRow]);
            if (tag === ValueTag.Empty) {
                continue;
            }
            const absoluteRow = page.rowStart + localRow;
            const offset = absoluteRow - minRow;
            switch (tag) {
                case ValueTag.Number:
                    kindCodes[offset] = NUMERIC_KIND;
                    numericValues[offset] = normalizeExactLookupNumber(page.numbers[localRow] ?? 0);
                    break;
                case ValueTag.Boolean:
                    kindCodes[offset] = BOOLEAN_KIND;
                    numericValues[offset] = (page.numbers[localRow] ?? 0) !== 0 ? 1 : 0;
                    break;
                case ValueTag.String:
                    kindCodes[offset] = TEXT_KIND;
                    textValues[offset] = args.normalizeStringId(page.stringIds[localRow] ?? 0);
                    break;
                case ValueTag.Error:
                    kindCodes[offset] = INVALID_KIND;
                    break;
                default:
                    break;
            }
        }
    });
    const owner = {
        sheetName: args.owner.sheetName,
        col: args.owner.col,
        columnVersion: args.owner.columnVersion,
        structureVersion: args.owner.structureVersion,
        sheetColumnVersions: args.owner.sheetColumnVersions,
        rowStart: minRow,
        rowEnd: maxRow,
        length,
        kindCodes,
        numericValues,
        textValues,
        firstPositions: new Map(),
        lastPositions: new Map(),
        rowLists: new Map(),
        sortedNumericAscendingBreaks: undefined,
        sortedNumericDescendingBreaks: undefined,
        numericUniformBreakOffsets: undefined,
        sortedTextAscendingBreaks: undefined,
        sortedTextDescendingBreaks: undefined,
        incompatibleNumericOffsets: undefined,
        incompatibleTextOffsets: undefined,
        exactNumericIncompatibleOffsets: undefined,
        exactTextIncompatibleOffsets: undefined,
        summariesDirty: true,
    };
    for (let offset = 0; offset < length; offset += 1) {
        const row = minRow + offset;
        const key = exactLookupKeyAt(owner, offset);
        insertOwnerKeyRow(owner, key, row);
    }
    initializeApproximateLookupSummaries(owner);
    return owner;
}
export function applyLookupColumnOwnerLiteralWrite(args) {
    if (args.write.row < args.owner.rowStart || args.write.row > args.owner.rowEnd) {
        return false;
    }
    const offset = args.write.row - args.owner.rowStart;
    const oldKey = exactLookupKeyForValue(args.write.oldValue, args.normalizeStringId, args.write.oldStringId);
    const newKey = exactLookupKeyForValue(args.write.newValue, args.normalizeStringId, args.write.newStringId);
    const deferApproximateSummaries = args.updateApproximateSummaries === false;
    const nextKind = kindCodeForValue(args.write.newValue);
    const nextNumericValue = numericValueForValue(args.write.newValue);
    const nextTextValue = args.write.newValue.tag === ValueTag.String
        ? textValueForValue(args.write.newValue, args.normalizeStringId, args.write.newStringId)
        : '';
    if (oldKey === newKey) {
        if (newKey !== undefined && !ownerKeyContainsRow(args.owner, newKey, args.write.row)) {
            return false;
        }
        if (ownerStoredComparableMatches(args.owner, offset, nextKind, nextNumericValue, nextTextValue)) {
            return true;
        }
    }
    else if (oldKey !== undefined) {
        if (!removeOwnerKeyRow(args.owner, oldKey, args.write.row)) {
            if (newKey === undefined || exactLookupKeyAt(args.owner, offset) !== newKey) {
                return false;
            }
        }
        else if (newKey !== undefined) {
            insertOwnerKeyRow(args.owner, newKey, args.write.row);
        }
    }
    else if (newKey !== undefined) {
        insertOwnerKeyRow(args.owner, newKey, args.write.row);
    }
    if (deferApproximateSummaries) {
        ensureExactLookupSummaries(args.owner);
    }
    const previousKind = decodeComparableKindCode(args.owner.kindCodes[offset]);
    args.owner.kindCodes[offset] = nextKind;
    args.owner.numericValues[offset] = nextNumericValue;
    if (args.write.newValue.tag === ValueTag.String) {
        args.owner.textValues[offset] = nextTextValue;
    }
    else if (offset < args.owner.textValues.length) {
        args.owner.textValues[offset] = '';
    }
    if (deferApproximateSummaries) {
        if (previousKind !== nextKind) {
            refreshExactLookupCompatibility(args.owner, offset);
        }
        refreshNumericUniformBreak(args.owner, offset);
        refreshNumericUniformBreak(args.owner, offset + 1);
        refreshNumericUniformBreak(args.owner, offset + 2);
        args.owner.summariesDirty = true;
        return true;
    }
    if (args.owner.summariesDirty) {
        initializeApproximateLookupSummaries(args.owner);
    }
    if (previousKind !== nextKind) {
        refreshApproximateLookupCompatibility(args.owner, offset);
    }
    refreshApproximateLookupBreaks(args.owner, offset);
    refreshApproximateLookupBreaks(args.owner, offset + 1);
    refreshNumericUniformBreak(args.owner, offset);
    refreshNumericUniformBreak(args.owner, offset + 1);
    refreshNumericUniformBreak(args.owner, offset + 2);
    args.owner.summariesDirty = false;
    return true;
}
function ensureApproximateLookupSummaries(owner) {
    if (!owner.summariesDirty &&
        owner.incompatibleNumericOffsets &&
        owner.incompatibleTextOffsets &&
        owner.exactNumericIncompatibleOffsets &&
        owner.exactTextIncompatibleOffsets &&
        owner.sortedNumericAscendingBreaks &&
        owner.sortedNumericDescendingBreaks &&
        owner.numericUniformBreakOffsets &&
        owner.sortedTextAscendingBreaks &&
        owner.sortedTextDescendingBreaks) {
        return;
    }
    initializeApproximateLookupSummaries(owner);
}
function ensureExactLookupSummaries(owner) {
    if (owner.exactNumericIncompatibleOffsets && owner.exactTextIncompatibleOffsets && owner.numericUniformBreakOffsets) {
        return;
    }
    initializeApproximateLookupSummaries(owner);
}
export function supportsNumericApproximateRange(owner, rowStart, rowEnd, matchMode) {
    ensureApproximateLookupSummaries(owner);
    const start = rowStart - owner.rowStart;
    const end = rowEnd - owner.rowStart;
    if (start < 0 || end >= owner.length) {
        return false;
    }
    if (hasOffsetInRange(owner.incompatibleNumericOffsets, start, end)) {
        return false;
    }
    return !hasOffsetInRange(matchMode === 1 ? owner.sortedNumericAscendingBreaks : owner.sortedNumericDescendingBreaks, start + 1, end);
}
export function supportsTextApproximateRange(owner, rowStart, rowEnd, matchMode) {
    ensureApproximateLookupSummaries(owner);
    const start = rowStart - owner.rowStart;
    const end = rowEnd - owner.rowStart;
    if (start < 0 || end >= owner.length) {
        return false;
    }
    if (hasOffsetInRange(owner.incompatibleTextOffsets, start, end)) {
        return false;
    }
    return !hasOffsetInRange(matchMode === 1 ? owner.sortedTextAscendingBreaks : owner.sortedTextDescendingBreaks, start + 1, end);
}
export function sliceOffsetBounds(owner, rowStart, rowEnd) {
    const start = rowStart - owner.rowStart;
    const end = rowEnd - owner.rowStart;
    if (start < 0 || end >= owner.length || start > end) {
        return undefined;
    }
    return { start, end };
}
export function summarizeExactRange(owner, rowStart, rowEnd) {
    ensureExactLookupSummaries(owner);
    const bounds = sliceOffsetBounds(owner, rowStart, rowEnd);
    if (!bounds) {
        return undefined;
    }
    const allNumeric = !hasOffsetInRange(owner.exactNumericIncompatibleOffsets, bounds.start, bounds.end);
    if (allNumeric) {
        const uniform = detectUniformNumericStepInOwner(owner, bounds.start, bounds.end);
        return {
            comparableKind: 'numeric',
            uniformStart: uniform?.start,
            uniformStep: uniform?.step,
        };
    }
    const allText = !hasOffsetInRange(owner.exactTextIncompatibleOffsets, bounds.start, bounds.end);
    if (allText) {
        return {
            comparableKind: 'text',
            uniformStart: undefined,
            uniformStep: undefined,
        };
    }
    return {
        comparableKind: 'mixed',
        uniformStart: undefined,
        uniformStep: undefined,
    };
}
export function summarizeApproximateRange(owner, rowStart, rowEnd) {
    const bounds = sliceOffsetBounds(owner, rowStart, rowEnd);
    if (!bounds) {
        return undefined;
    }
    const numericAscending = supportsNumericApproximateRange(owner, rowStart, rowEnd, 1);
    const numericDescending = supportsNumericApproximateRange(owner, rowStart, rowEnd, -1);
    if (numericAscending || numericDescending) {
        const uniform = detectUniformNumericStepInOwner(owner, bounds.start, bounds.end);
        const repeatedUniform = uniform === undefined ? detectRepeatedUniformNumericStepInOwner(owner, bounds.start, bounds.end) : undefined;
        return {
            comparableKind: 'numeric',
            uniformStart: uniform?.start,
            uniformStep: uniform?.step,
            repeatedUniformStart: repeatedUniform?.start,
            repeatedUniformStep: repeatedUniform?.step,
            repeatedUniformRunLength: repeatedUniform?.runLength,
            sortedAscending: numericAscending,
            sortedDescending: numericDescending,
        };
    }
    const textAscending = supportsTextApproximateRange(owner, rowStart, rowEnd, 1);
    const textDescending = supportsTextApproximateRange(owner, rowStart, rowEnd, -1);
    if (textAscending || textDescending) {
        return {
            comparableKind: 'text',
            uniformStart: undefined,
            uniformStep: undefined,
            repeatedUniformStart: undefined,
            repeatedUniformStep: undefined,
            repeatedUniformRunLength: undefined,
            sortedAscending: textAscending,
            sortedDescending: textDescending,
        };
    }
    return {
        comparableKind: undefined,
        uniformStart: undefined,
        uniformStep: undefined,
        repeatedUniformStart: undefined,
        repeatedUniformStep: undefined,
        repeatedUniformRunLength: undefined,
        sortedAscending: false,
        sortedDescending: false,
    };
}
//# sourceMappingURL=lookup-column-owner.js.map