import { ValueTag } from '@bilig/protocol';
import { parseRangeAddress } from '@bilig/formula';
export function getColumnCacheKey(sheetName, col, rowStart, rowEnd) {
    return `${sheetName}\t${col}\t${rowStart}\t${rowEnd}`;
}
export function normalizeApproximateComparableValue(value, lookupString, stringId = 0) {
    switch (value.tag) {
        case ValueTag.Empty:
            return { kind: 'empty' };
        case ValueTag.Number:
            return { kind: 'numeric', value: Object.is(value.value, -0) ? 0 : value.value };
        case ValueTag.Boolean:
            return { kind: 'numeric', value: value.value ? 1 : 0 };
        case ValueTag.String:
            return {
                kind: 'text',
                value: (stringId !== 0 ? lookupString(stringId) : value.value).toUpperCase(),
            };
        case ValueTag.Error:
            return { kind: 'invalid' };
    }
}
export function compareApproximateNumeric(left, right) {
    if (left === right) {
        return 0;
    }
    return left < right ? -1 : 1;
}
export function compareApproximateText(left, right) {
    if (left === right) {
        return 0;
    }
    return left < right ? -1 : 1;
}
export function findUniformNumericApproximatePosition(args) {
    if (args.uniformStart === undefined || args.uniformStep === undefined) {
        return { handled: false };
    }
    if (args.length <= 0) {
        return { handled: true, position: undefined };
    }
    const { lookupValue, length, matchMode, uniformStart, uniformStep } = args;
    const lastValue = uniformStart + uniformStep * (length - 1);
    if (matchMode === 1 && uniformStep > 0) {
        if (lookupValue < uniformStart) {
            return { handled: true, position: undefined };
        }
        if (lookupValue >= lastValue) {
            return { handled: true, position: length };
        }
        const position = Math.floor((lookupValue - uniformStart) / uniformStep) + 1;
        return { handled: true, position: Math.min(length, Math.max(1, position)) };
    }
    if (matchMode === -1 && uniformStep < 0) {
        if (lookupValue > uniformStart) {
            return { handled: true, position: undefined };
        }
        if (lookupValue <= lastValue) {
            return { handled: true, position: length };
        }
        const position = Math.floor((uniformStart - lookupValue) / -uniformStep) + 1;
        return { handled: true, position: Math.min(length, Math.max(1, position)) };
    }
    return { handled: false };
}
export function findRepeatedUniformNumericApproximatePosition(args) {
    if (args.repeatedUniformStart === undefined || args.repeatedUniformStep === undefined || args.repeatedUniformRunLength === undefined) {
        return { handled: false };
    }
    if (args.length <= 0) {
        return { handled: true, position: undefined };
    }
    const { lookupValue, length, matchMode, repeatedUniformStart, repeatedUniformStep, repeatedUniformRunLength } = args;
    const groupCount = Math.ceil(length / repeatedUniformRunLength);
    const lastValue = repeatedUniformStart + repeatedUniformStep * (groupCount - 1);
    if (matchMode === 1 && repeatedUniformStep > 0) {
        if (lookupValue < repeatedUniformStart) {
            return { handled: true, position: undefined };
        }
        if (lookupValue >= lastValue) {
            return { handled: true, position: length };
        }
        const group = Math.floor((lookupValue - repeatedUniformStart) / repeatedUniformStep);
        return { handled: true, position: Math.min(length, (group + 1) * repeatedUniformRunLength) };
    }
    if (matchMode === -1 && repeatedUniformStep < 0) {
        if (lookupValue > repeatedUniformStart) {
            return { handled: true, position: undefined };
        }
        if (lookupValue <= lastValue) {
            return { handled: true, position: length };
        }
        const group = Math.floor((repeatedUniformStart - lookupValue) / -repeatedUniformStep);
        return { handled: true, position: Math.min(length, (group + 1) * repeatedUniformRunLength) };
    }
    return { handled: false };
}
export function supportsPreparedApproximateKind(prepared, kind, matchMode) {
    return prepared.comparableKind === kind && (matchMode === 1 ? prepared.sortedAscending : prepared.sortedDescending);
}
export function detectUniformNumericStep(values) {
    if (values.length < 2) {
        return undefined;
    }
    const start = values[0];
    const step = values[1] - start;
    if (!Number.isFinite(step) || step === 0) {
        return undefined;
    }
    for (let index = 2; index < values.length; index += 1) {
        if (values[index] - values[index - 1] !== step) {
            return undefined;
        }
    }
    return { start, step };
}
export function detectRepeatedUniformNumericStep(values) {
    if (values.length < 4) {
        return undefined;
    }
    const start = values[0];
    let runLength = 1;
    while (runLength < values.length && values[runLength] === start) {
        runLength += 1;
    }
    if (runLength <= 1 || runLength >= values.length) {
        return undefined;
    }
    const step = values[runLength] - start;
    if (!Number.isFinite(step) || step === 0) {
        return undefined;
    }
    for (let index = 0; index < values.length; index += 1) {
        const group = Math.floor(index / runLength);
        if (values[index] !== start + step * group) {
            return undefined;
        }
    }
    return { start, step, runLength };
}
export 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;
    }
}
export function resolveSingleColumnBounds(request) {
    if (request.startRow !== undefined && request.endRow !== undefined && request.startCol !== undefined && request.endCol !== undefined) {
        if (request.startCol !== request.endCol) {
            return undefined;
        }
        return {
            rowStart: request.startRow,
            rowEnd: request.endRow,
            col: request.startCol,
        };
    }
    const parsedRange = parseRangeAddress(`${request.start}:${request.end}`, request.sheetName);
    if (parsedRange.kind !== 'cells' || parsedRange.start.col !== parsedRange.end.col) {
        return undefined;
    }
    return {
        rowStart: parsedRange.start.row,
        rowEnd: parsedRange.end.row,
        col: parsedRange.start.col,
    };
}
export function columnRegistryKey(sheetName, col) {
    return `${sheetName}\t${col}`;
}
//# sourceMappingURL=sorted-column-search-helpers.js.map