import { ValueTag, formatErrorCode, formatGeneralNumberValue } from '@bilig/protocol';
import { parseArithmeticScalarText } from '@bilig/formula';
const ROUND_HALF_TOLERANCE = 1e-12;
export function inlineRequiredNumber(value) {
    return value.tag === ValueTag.Error ? undefined : inlineNumber(value);
}
export function inlineOptionalNumber(value, fallback) {
    return value === undefined ? fallback : inlineRequiredNumber(value);
}
export function inlinePaymentType(value, fallback) {
    const numeric = inlineOptionalNumber(value, fallback);
    if (numeric === undefined) {
        return undefined;
    }
    const type = Math.trunc(numeric);
    return type === 0 || type === 1 ? type : undefined;
}
export function roundInlineToDigits(value, digits) {
    if (digits >= 0) {
        const factor = 10 ** digits;
        return roundScaledHalfAwayFromZero(value * factor) / factor;
    }
    const factor = 10 ** -digits;
    return roundScaledHalfAwayFromZero(value / factor) * factor;
}
function roundScaledHalfAwayFromZero(value) {
    const sign = value < 0 ? -1 : 1;
    const absolute = Math.abs(value);
    const floor = Math.floor(absolute);
    const fraction = absolute - floor;
    const rounded = Math.abs(fraction - 0.5) <= ROUND_HALF_TOLERANCE ? floor + 1 : Math.round(absolute);
    return sign * rounded;
}
export function inlineNumber(value) {
    switch (value.tag) {
        case ValueTag.Number:
            return value.value;
        case ValueTag.Boolean:
            return value.value ? 1 : 0;
        case ValueTag.Empty:
            return 0;
        case ValueTag.String:
        case ValueTag.Error:
        default:
            return undefined;
    }
}
export function inlineArithmeticNumber(value, dateSystem = '1900') {
    if (value.tag !== ValueTag.String) {
        return inlineNumber(value);
    }
    return parseArithmeticScalarText(value.value, dateSystem);
}
export function inlineTruthy(value) {
    return (inlineNumber(value) ?? 0) !== 0;
}
export function inlineStringValue(value) {
    switch (value.tag) {
        case ValueTag.Empty:
            return '';
        case ValueTag.Number:
            return formatGeneralNumberValue(value.value);
        case ValueTag.Boolean:
            return value.value ? 'TRUE' : 'FALSE';
        case ValueTag.String:
            return value.value;
        case ValueTag.Error:
            return formatErrorCode(value.code);
    }
}
export function compareInlineScalars(left, right) {
    if (left.tag === ValueTag.String && right.tag === ValueTag.String) {
        return compareInlineText(left.value, right.value);
    }
    if (left.tag === ValueTag.Empty && right.tag === ValueTag.Empty) {
        return 0;
    }
    if (left.tag === ValueTag.String && right.tag === ValueTag.Empty) {
        return compareInlineText(left.value, '');
    }
    if (left.tag === ValueTag.Empty && right.tag === ValueTag.String) {
        return compareInlineText('', right.value);
    }
    if (left.tag === ValueTag.String && isInlineNumberLike(right)) {
        return 1;
    }
    if (isInlineNumberLike(left) && right.tag === ValueTag.String) {
        return -1;
    }
    const leftNumber = inlineNumber(left);
    const rightNumber = inlineNumber(right);
    if (leftNumber === undefined || rightNumber === undefined) {
        return undefined;
    }
    if (leftNumber === rightNumber || (Object.is(leftNumber, -0) && Object.is(rightNumber, 0))) {
        return 0;
    }
    return leftNumber < rightNumber ? -1 : 1;
}
function isInlineNumberLike(value) {
    return value.tag === ValueTag.Number || value.tag === ValueTag.Boolean;
}
function compareInlineText(left, right) {
    const normalizedLeft = left.toUpperCase();
    const normalizedRight = right.toUpperCase();
    if (normalizedLeft === normalizedRight) {
        return 0;
    }
    return normalizedLeft < normalizedRight ? -1 : 1;
}
//# sourceMappingURL=formula-leaf-inline-scalar-values.js.map