@use 'sass:list';
@use 'sass:map';
@use 'sass:math';
@use 'sass:meta';
@use 'sass:string';
@use '../../string/str-split/str-split.scss' as *;
@use '../../string/str-trim/str-trim.scss' as *;
@use '../../list/list-slice/list-slice.scss' as *;
@use '../../../variables' as vars;

@function _local-intval($value) {
	$number: 0;
	$digits: ('0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9);

	@for $i from 1 through string.length($value) {
		$char: string.slice($value, $i, $i);
		$num: if(map.has-key($digits, $char), map.get($digits, $char), null);

		@if (not $num) {
			@return null;
		}

		$number: $number * 10 + $num;
	}

	@return $number;
}

/**
 * Transforms a given pseudo-number string to a real number.
 *
 * @param    {string|number}    $string    The input value.
 *
 * @return   {?number}    Numeric value or null if value is not a valid number.
 */
@function get-numeric($value) {
	@if (meta.type-of($value) == 'number') {
		@return $value;
	}

	$value: str-trim(#{$value});

	$k: 1;
	$integral: 0;
	$fractional: 0;
	$exponential: 1;
	$unit: 1;

	// Get unit
	$_units: map.keys(vars.$units);

	@while (list.length($_units) > 0) {
		$_unit: list.nth($_units, 1);
		$_units: list-slice($_units, 2);

		@if (string.slice($value, string.length($_unit) * -1) == $_unit) {
			$unit: map.get(vars.$units, $_unit);
			$value: string.slice($value, 1, (string.length($_unit) + 1) * -1);

			$_units: ();
		}
	}

	// Check positive/negative
	@if (list.index(('+', '-'), string.slice($value, 1, 1))) {
		$k: if(string.slice($value, 1, 1) == '-', -1, 1);
		$value: string.slice($value, 2);
	}

	// Get exponential part
	$exp-k: 1;
	$exp-num: 0;

	@if (string.index($value, 'e')) {
		$split: str-split($value, 'e');
		$before: list.nth($split, 1);
		$after: if(list.length($split) == 2, list.nth($split, 2), '');

		@if ($before == '' or $after == '') {
			@return null;
		}

		$exp-k: if(string.index($after, '-') == 1, -1, 1);
		$exp-num: _local-intval(if(string.index($after, '-') == 1, string.slice($after, 2), $after));

		@if (not $exp-num) {
			@return null;
		}

		$value: $before;
		$exponential: math.pow(10, $exp-num * $exp-k);
	}

	// Get integral and fractional part
	$integral: 0;
	$fractional: 0;

	@if (string.index($value, '.')) {
		$split: str-split($value, '.');
		$before: list.nth($split, 1);
		$after: if(list.length($split) == 2, list.nth($split, 2), '');

		@if ($after == '') {
			@return null;
		}

		$integral: _local-intval(if($before == '', '0', $before));
		$fractional: _local-intval($after);

		@if (not $integral or not $fractional) {
			@return null;
		} @else {
			$fractional: math.div($fractional, math.pow(10, string.length($after)));
		}
	} @else {
		$integral: _local-intval($value);

		@if (not $integral) {
			@return null;
		}
	}

	@return ($integral + $fractional) * $exponential * $k * $unit;
}
