// RIVER Design-System: System - Functions / Maps //

// Functionality for interacting with our design system maps.
// The design system heirachy is: map > group > range (optional) > value.
// Our default map (and groups) is defined in 'system/design-maps'.


// MAPS, GROUPS, RANGES
// Retrieve and update design maps, group, and ranges

// Get a design map (by group, or the entire map)
@function design-map($groupKey: null, $throwException: false) {
    @if($groupKey and map-has-key($design-map, $groupKey)) {
        @return map-get($design-map, $groupKey);
    }
    @if($groupKey) {
        @if($throwException) {
            @error("design-map() invalid group key '#{$groupKey}' not found");
        }
        @warn("design-map() requested group key '#{$groupKey}' not found");
        @return null;
    }
    @return $design-map;
}

// Set the given $groupMap onto the $groupKey in the design system
// This overrides the existing group completely
// NOTE, you need to update the existing $design-map with the updated design map returned
// eg, $design-map: design-group-set('colors', ('brand-primary': (...), 'grayscale': (...)));
@function design-map-set($groupKey, $groupMap) {
    $design-map: design-map();
    @if(not map-has-key($design-map, $groupKey)) {
        @warn("design-map-set() specified group key '#{$groupKey}' not found, new group map created");
    }
    $design-map: map-set($design-map, $groupKey, $groupMap);
    @return $design-map;
}

// Update the existing $groupKey design map with the values in $groupMap
@function design-map-update($groupKey, $groupMap) {
    $design-map: design-map();
    @if(map-has-key($design-map, $groupKey)) {
        $groupMap: map-merge(map-get($design-map, $groupKey), $groupMap);
    } @else {
        @warn("design-map-update() specified group key '#{$groupKey}' not found, new group map created");
    }
    $design-map: map-set($design-map, $groupKey, $groupMap);
    @return $design-map;
}

// Perform a deep update on the existing $groupKey design map with the values in $groupMap
@function design-map-deep-update($groupKey, $groupMap) {
    $design-map: design-map();
    @if(map-has-key($design-map, $groupKey)) {
        $groupMap: map-deep-merge(map-get($design-map, $groupKey), $groupMap);
    } @else {
        @warn("design-map-update() specified group key '#{$groupKey}' not found, new group map created");
    }
    $design-map: map-set($design-map, $groupKey, $groupMap);
    @return $design-map;
}

@function design-map-setting($groupKey, $settingKey, $default: null) {
    $design-map: design-map();
    $settingKey: '_' + $settingKey;
    @if(not map-has-key($design-map, $groupKey)) {
        @warn("design-map-setting() specified group key '#{$groupKey}' not found");
        @return $default;
    }
    $design-group: map-get($design-map, $groupKey);
    $settingValue: if(map-has-key($design-group, $settingKey), map-get($design-group, $settingKey), $default);
    @return $settingValue;
}

// Get a map for a particular design group
// eg, design-group ('colors')
@function design-group($groupKey, $throwException: false) {
    @if(not map-has-key(design-map(), $groupKey)) {
        @if($throwException) {
            @error("design-group() invalid group key '#{$groupKey}' not found");
        }
        @warn("design-group() requested group key '#{$groupKey}' not found");
        @return null;
    }
    @return map-get(design-map(), $groupKey);
}

// Set the given $groupMap onto the $groupKey in the design system
// Overrides the existing group completely
// NOTE, you'll need to update the existing $design-map with the updated design map returned
// eg, $design-map: design-group-set('colors', ('brand-primary': (...), 'grayscale': (...)));
// DISABLED until we confirm if this is additional function is useful
// @function design-group-set($groupKey, $groupMap) {
//     $design-map: design-map();
//     $design-map: map-set($design-map, $groupKey, $groupMap);
//     @return $design-map;
// }

// Get a map for a particular design range
// eg, design-range('colors.brand-primary')
@function design-range($rangeKey, $throwException: false) {
    // Note and validate the design group (infer one if needed)
    // eg, 'colors'; null if not matched
    $groupKey: _design-key-group($rangeKey);
    @if(not($groupKey)) {
        @if($throwException) {
            @error("design-range() unable to match a group from the key #{$rangeKey}");
        }
        @warn("design-range() unable to match a group from the key '#{$rangeKey}'");
        @return null;
    }

    // Look for the range
    $rangeKey: str-replace($rangeKey, $groupKey + '.', '');
    $range: map-deep-get(design-group($groupKey), $rangeKey);

    // Validate
    @if(not($range)) {
        @if($throwException) {
            @error("design-range() unable to match a range from the key '#{$rangeKey}'");
        }
        @warn("design-range() unable to match a range from the key '#{$rangeKey}'");
        @return null;
    }

    // Return
    @return $range;
}

// Set the given $rangeValues onto the $rangeKey in the design system
// Overrides the existing range completely
// NOTE, you'll need to update the existing $design-map with the updated design map returned
// eg, $design-map: design-range-set('colors.brand-primary', (900: ..., 800: ..., ...));
// DISABLED until we confirm if this is additional function is useful
// @function design-range-set($rangeKey, $rangeValues) {
//     // Set the $rangeValues recursively
//     // eg, 'colors.brand-primary.normal' => colors: ( brand-primary: (normal: ... ) )
//     $design-map: map-deep-set(design-map(), $rangeKey, $rangeValues);

//     // Return the updated design map
//     @return $design-map;
// }
