import { describe, expect, it } from "vitest";
import { extractSourceTokens, refineTokenPayload } from "./index.js";
import type { ParsedToken, RepoTreeEntry } from "./types.js";

describe("extractSourceTokens", () => {
  it("extracts tokens and hardcoded-value findings from an injected file store", async () => {
    const files = {
      "src/styles/tokens.css": [
        ":root {",
        "  --color-primary: #0f62fe;",
        "  --space-md: 12px;",
        "}",
      ].join("\n"),
      "src/components/Button.module.css": [
        ".button {",
        "  color: #0f62fe;",
        "  padding: var(--space-md);",
        "}",
      ].join("\n"),
    };

    const result = await extractSourceTokens({
      tree: treeFromFiles(files),
      fileStore: memoryFileStore(files),
    });

    expect(result.tokenCount).toBe(2);
    expect(result.tokenFileCount).toBe(1);
    expect(result.parsedTokens.map((token) => token.name)).toEqual([
      "--color-primary",
      "--space-md",
    ]);
    expect(result.hardcodedFindings).toEqual([
      expect.objectContaining({
        file: "src/components/Button.module.css",
        hardcodedValue: "#0f62fe",
        suggestedToken: "--color-primary",
      }),
    ]);
  });

  it("inherits prior tokens without refetching their files", async () => {
    const files = {
      "src/styles/new.css": ":root { --color-secondary: #ff00aa; }\n",
      "src/components/Card.module.css": ".card {\n  color: #0f62fe;\n}\n",
    };
    const priorToken = token("--color-primary", "#0f62fe", "src/tokens/old.tokens.json");
    const readPaths: string[] = [];

    const result = await extractSourceTokens({
      tree: [
        { path: "src/tokens/old.tokens.json", type: "blob", size: 42 },
        ...treeFromFiles(files),
      ],
      fileStore: {
        async getText(path) {
          readPaths.push(path);
          return files[path as keyof typeof files] ?? null;
        },
      },
      priorParsedTokens: [priorToken],
      priorTokenFilePaths: new Set(["src/tokens/old.tokens.json"]),
    });

    expect(readPaths).not.toContain("src/tokens/old.tokens.json");
    expect(result.parsedTokens.map((parsed) => parsed.name)).toEqual([
      "--color-primary",
      "--color-secondary",
    ]);
    expect(result.hardcodedFindings[0]?.suggestedToken).toBe("--color-primary");
  });

  it("refines token counts with provenance classification", () => {
    const refined = refineTokenPayload(
      [
        token("--fui-color-primary", "#0f62fe", "packages/ui/tokens.css"),
        token("--consumer-color", "#ff00aa", "apps/web/theme.css"),
      ],
      {
        primarySources: ["packages/ui/tokens.css"],
        appPaths: ["apps/web"],
        prefix: "fui",
      }
    );

    expect(refined.tokenCount).toBe(2);
    expect(refined.canonicalCount).toBe(1);
  });
});

function treeFromFiles(files: Record<string, string>): RepoTreeEntry[] {
  return Object.entries(files).map(([path, content]) => ({
    path,
    type: "blob",
    size: content.length,
  }));
}

function memoryFileStore(files: Record<string, string>) {
  return {
    async getText(path: string) {
      return files[path] ?? null;
    },
  };
}

function token(name: string, value: string, file: string): ParsedToken {
  return {
    name,
    value,
    category: "color",
    file,
    line: 1,
    tier: "unknown",
    identityKey: name,
  };
}
