// ---------- string helpers ----------
@function s_str($v) { @return #{$v}; }
@function s_starts_with($s, $prefix) { @return string.index($s, $prefix) == 1; }
@function s_after($s, $prefix) { @return string.slice($s, string.length($prefix) + 1); }
@function s_contains($s, $needle) { @return string.index($s, $needle) != null; }
@function s_first_dash($s) { @return string.index($s, "-"); }

// join path + segment with "-" (skip empty bits)
@function s_join($a, $b) {
  @if ($a == null or $a == "") { @return $b; }
  @if ($b == null or $b == "") { @return $a; }
  @return $a + "-" + $b;
}

// remove trailing "-default" (e.g. "theme-default" -> "theme")
@function s_trim_default($name) {
  @if $name == null { @return $name; }
  $suffix: "-default";
  $i: string.index($name, $suffix);
  @if $i != null and $i == string.length($name) - string.length($suffix) + 1 {
    @return string.slice($name, 1, string.length($name) - string.length($suffix));
  }
  @return $name;
}

// ---------- set/map helpers ----------
@function s_set_put($set, $key) { @return map.merge($set, ( $key: true )); }
@function s_set_has($set, $key) { @return map.has-key($set, $key); }

@function s_is_scalar($v) {
  $t: meta.type-of($v);
  @return $v != null and $v != "" and $t != 'map';
}

@function s_has_raw_theme_token($name) { @return s_contains($name, "--"); }

// ---------- global state ----------
$g_base: () !default;           // name -> scalar value
$g_root: () !default;           // set(name) → :root
$g_themes: () !default;         // theme -> (name -> scalar value)
$g_exclude_theme: () !default;  // set(name) excluded from @theme (via "!")

// $s_theme_keys: ('dark','light',...) is injected by your wrapper

// ---------- recursive collector ----------
@mixin s_collect($mapVal, $path: "", $promote: false, $forceRoot: false) {
  @each $rawKey, $val in $mapVal {
    $k: s_str($rawKey);

    // Themed override: --dark-<suffix>
    @if s_starts_with($k, "--") and s_contains($k, "-") and meta.type-of($val) != 'map' {
      $tmp: s_after($k, "--");
      $dash: s_first_dash($tmp);
      @if $dash != null {
        $theme: string.slice($tmp, 1, $dash - 1);
        $rest: string.slice($tmp, $dash + 1);        // "default" | "50" | "foo" ...
        $namePart: if($rest == "default", "", $rest);
        $varName: s_trim_default(s_join($path, $namePart));
        @if list.index($s_theme_keys, $theme) {
          $bucket: map.get($g_themes, $theme);
          @if $bucket == null { $bucket: (); }
          $bucket: map.merge($bucket, ( $varName: $val ));
          $g_themes: map.merge($g_themes, ( $theme: $bucket )) !global;

          // base must be in :root if there’s a themed override
          $g_root: s_set_put($g_root, $varName) !global;

          // ensure base exists (sane fallback)
          @if not map.has-key($g_base, $varName) {
            $g_base: map.merge($g_base, ( $varName: $val )) !global;
          }

          // respect "!" forcing exclusion from @theme
          @if $forceRoot {
            $g_exclude_theme: s_set_put($g_exclude_theme, $varName) !global;
          }
        } @else {
          // unknown theme → keep raw key in base, never promote
          $kept: s_join($path, $k);
          @if not map.has-key($g_base, $kept) {
            $g_base: map.merge($g_base, ( $kept: $val )) !global;
          }
        }
      }
      @continue;
    }

    // "#" promote subtree
    $segPromote: false;
    @if s_starts_with($k, "#") { $segPromote: true; $k: s_after($k, "#"); }

    // "!" force :root + exclude from @theme for subtree
    $segForceRoot: false;
    @if s_starts_with($k, "!") { $segForceRoot: true; $k: s_after($k, "!"); }

    // Descend
    @if meta.type-of($val) == 'map' {
      $nextPath: if($k == "default", $path, s_join($path, $k));
      @include s_collect($val, $nextPath, $promote or $segPromote, $forceRoot or $segForceRoot);
      @continue;
    }

    // Leaf
    $leafName: if($k == "default", $path, s_join($path, $k));
    @if $leafName != null and $leafName != "" and s_is_scalar($val) {
      $g_base: map.merge($g_base, ( $leafName: $val )) !global;
      @if $promote or $segPromote or $forceRoot or $segForceRoot {
        $g_root: s_set_put($g_root, $leafName) !global;
      }
      @if $forceRoot or $segForceRoot {
        $g_exclude_theme: s_set_put($g_exclude_theme, $leafName) !global;
      }
    }
  }
}

// ---------- cleaning ----------
@mixin s_clean() {
  // base: drop non‑scalars & raw theme token names
  $__base: ();
  @each $name, $value in $g_base {
    @if s_is_scalar($value) and not s_has_raw_theme_token($name) {
      $__base: map.merge($__base, ($name: $value));
    }
  }
  $g_base: $__base !global;

  // root: keep only names that survived in base
  $__root: ();
  @each $name, $flag in $g_root {
    @if not s_has_raw_theme_token($name) and map.has-key($g_base, $name) {
      $__root: map.merge($__root, ($name: true));
    }
  }
  $g_root: $__root !global;

  // exclude set: drop raw token names
  $__ex: ();
  @each $name, $flag in $g_exclude_theme {
    @if not s_has_raw_theme_token($name) {
      $__ex: map.merge($__ex, ($name: true));
    }
  }
  $g_exclude_theme: $__ex !global;

  // themes: keep only clean scalars
  $__themes: ();
  @each $theme, $vars in $g_themes {
    $__t: ();
    @each $n, $v in $vars {
      @if s_is_scalar($v) and not s_has_raw_theme_token($n) {
        $__t: map.merge($__t, ($n: $v));
      }
    }
    $__themes: map.merge($__themes, ($theme: $__t));
  }
  $g_themes: $__themes !global;
}

// ---------- emit ----------
@mixin s_emit() {
  // 1) :root — only promoted names
  :root {
    @each $name, $flag in $g_root {
      --#{$name}: #{map.get($g_base, $name)};
    }
  }

  // 2) Theme classes
  @each $theme, $vars in $g_themes {
    .#{$theme} {
      @each $name, $value in $vars {
        --#{$name}: #{$value};
      }
    }
  }

  // 3) @theme — union (FILTERED) of base names and themed names
  // Start with base, SKIPPING excluded
  $__all: ();
  @each $n, $v in $g_base {
    @if not s_set_has($g_exclude_theme, $n) {
      $__all: map.merge($__all, ($n: $v));
    }
  }
  // Add any names referenced only by theme overrides, SKIPPING excluded
  @each $t, $vars in $g_themes {
    @each $n, $v in $vars {
      @if not s_set_has($g_exclude_theme, $n) and not map.has-key($__all, $n) {
        $__all: map.merge($__all, ($n: if(map.has-key($g_base, $n), map.get($g_base, $n), $v)));
      }
    }
  }

  @theme {
    @each $name, $value in $__all {
      @if map.has-key($g_root, $name) {
        --color-#{$name}: var(--#{$name});
      } @else {
        --color-#{$name}: #{$value};
      }
    }
  }
}

// ---------- public entry ----------
@mixin s_walk_colors($rootMap) {
  // reset
  $g_base: () !global;
  $g_root: () !global;
  $g_themes: () !global;
  $g_exclude_theme: () !global;

  // collect deep
  @include s_collect($rootMap, "", false, false);

  // If any name has a known theme override, ensure it is promoted to :root
  @each $theme, $vars in $g_themes {
    @each $n, $v in $vars {
      $g_root: s_set_put($g_root, $n) !global;
    }
  }

  // clean and emit
  @include s_clean();
  @include s_emit();
}