@use "sass:string";
@use "sass:math";
@use "sass:map";
@use "sass:list";
@use "sass:meta";
@use "../config/constants" as config-constants;
@use "./strings" as fn-strings;

// Module-level constant - created once, not per function call
$digit-map: (
    "0": 0,
    "1": 1,
    "2": 2,
    "3": 3,
    "4": 4,
    "5": 5,
    "6": 6,
    "7": 7,
    "8": 8,
    "9": 9,
);

// Raw number parsing - returns (number, remaining-string) tuple
@function to-number-raw($value) {
    @if meta.type-of($value) == "number" {
        @return ($value, "");
    } @else if meta.type-of($value) != "string" {
        @error "Value for `to-number-raw` should be a number or a string.";
        @return null;
    }

    $val: string.unquote(fn-strings.strip-quotes($value));

    $result: 0;
    $digits: 0;
    $minus: string.slice($val, 1, 1) == "-";
    $sign: 1;
    $start-index: 1;

    @if $minus {
        $sign: -1;
        $start-index: 2;
    }

    @for $i from $start-index through string.length($val) {
        $character: string.slice($val, $i, $i);

        @if list.index(map.keys($digit-map), $character) or $character == "." {
            @if $character == "." {
                $digits: 1;
            } @else if $digits == 0 {
                $result: $result * 10 + map.get($digit-map, $character);
            } @else {
                $digits: $digits * 10;
                $result: $result + math.div(map.get($digit-map, $character), $digits);
            }
        } @else {
            @if $i == $start-index {
                @return null;
            }
            @return (($sign * $result), string.slice($val, $i));
        }
    }

    @return (($sign * $result), "");
}

// Full conversion with unit handling - calls to-number-raw internally
@function to-number($value, $append-unit: null) {
    $parsed: to-number-raw($value);
    @if not $parsed {
        @return null;
    }

    $number: list.nth($parsed, 1);

    @if $append-unit {
        @return $number + $append-unit;
    }

    $rest: list.nth($parsed, 2);
    @if $rest == "" {
        @return $number;
    }

    // Check if remaining string is a valid unit
    @each $unit in config-constants.$units {
        @if $rest == $unit {
            @return $number + string.unquote($unit);
        }
    }

    // No valid unit found, return just the number
    @return $number;
}
