export interface TokenEntry {
  /** 그룹을 뗀 토큰 이름 (`--fox-color-background-default` → `background-default`) */
  name: string;
  /**
   * 현재 테마·뷰포트에서 실제로 해석된 값 (`#FFFFFF`, `1.6rem`).
   *
   * 선언 원문이 아니라 계산값을 쓴다 — 색상은 Lightning CSS가 `light-dark()`를
   * `var(--lightningcss-light, …) var(--lightningcss-dark, …)`로 폴리필해 내보내므로
   * 원문이 읽기 어렵고, 크기는 alias가 `var(--fox-…)` 참조라 원문만으로는 값을 알 수
   * 없다. 계산값은 지금 화면에 실제로 적용되는 값과 정확히 일치한다.
   */
  value: string;
  /** 스타일에서 참조할 커스텀 프로퍼티 전체 이름 */
  property: string;
}

export type TokenRegistry = Record<string, TokenEntry[]>;

const PREFIX = "--fox-";

/**
 * 문서의 모든 스타일시트를 훑어 `--fox-*` 커스텀 프로퍼티를 그룹별로 모은다.
 *
 * 테스트 페이지가 토큰 목록을 따로 들고 있지 않게 하려는 것이 목적이다 — `tokens/`에
 * 값을 추가하면 여기에 자동으로 나타나고, 목록이 두 곳에 존재해 어긋날 일이 없다.
 * CSSOM은 선언 순서를 보존하므로 SCSS map에 적은 순서가 그대로 유지된다.
 *
 * 브라우저에서만 동작한다(문서가 있어야 한다).
 */
export function readTokenRegistry(): TokenRegistry {
  const registry: TokenRegistry = {};
  const seen = new Set<string>();
  // 이름·순서는 CSSOM 규칙에서, 값은 계산 스타일에서 가져온다.
  const computed = getComputedStyle(document.documentElement);

  for (const sheet of Array.from(document.styleSheets)) {
    let rules: CSSRuleList;
    try {
      rules = sheet.cssRules;
    } catch {
      // 교차 출처 스타일시트는 규칙을 읽을 수 없다 — 우리 토큰은 동일 출처이므로 건너뛴다.
      continue;
    }

    for (const rule of Array.from(rules)) {
      if (!(rule instanceof CSSStyleRule) || rule.selectorText !== ":root") {
        continue;
      }

      for (const property of Array.from(rule.style)) {
        if (!property.startsWith(PREFIX) || seen.has(property)) {
          continue;
        }
        seen.add(property);

        const rest = property.slice(PREFIX.length);
        const separator = rest.indexOf("-");
        if (separator <= 0) {
          continue;
        }

        (registry[rest.slice(0, separator)] ??= []).push({
          name: rest.slice(separator + 1),
          value:
            computed.getPropertyValue(property).trim() ||
            rule.style.getPropertyValue(property).trim(),
          property,
        });
      }
    }
  }

  return registry;
}
