import { describe, expect, it } from "vitest";

import { createMemoryScanSource } from "./memory-source.js";
import { extractQuickComponentCandidatesFromSource } from "./quick-component-candidates.js";

describe("extractQuickComponentCandidatesFromSource", () => {
  it("extracts only syntax-local exported component candidates", async () => {
    const files = {
      "src/Button.tsx": ["export function Button() {", "  return <button />;", "}"].join("\n"),
      "src/Link.tsx": [
        "import { forwardRef } from 'react';",
        "export const Link = forwardRef(function LinkInner(_props, ref) {",
        "  return <a ref={ref} />;",
        "});",
      ].join("\n"),
      "src/Card.tsx": ["function Card() {", "  return <section />;", "}", "export { Card };"].join(
        "\n"
      ),
      "src/Badge.tsx": ["export default function Badge() {", "  return <span />;", "}"].join("\n"),
      "src/Avatar.tsx": 'export default () => <img alt="" />;',
      "src/Accordion/index.vue": "<template><section /></template>",
      "src/helpers.ts": [
        "export const buildClassName = () => 'x';",
        "export function lowerCase() { return null; }",
      ].join("\n"),
      "src/index.ts": "export { Button } from './Button';",
    };

    const progress: Array<{
      filesProcessed: number;
      totalFiles: number;
      componentsFound: number;
    }> = [];
    const result = await extractQuickComponentCandidatesFromSource({
      source: createMemoryScanSource(files),
      files: Object.keys(files).map((relPath) => ({ relPath })),
      sourceCommit: "sha",
      adapterVersion: "quick-test",
      onProgress: (entry) => progress.push(entry),
    });

    expect(result.ucfs.map((ucf) => ucf.componentName).sort()).toEqual([
      "Accordion",
      "Avatar",
      "Badge",
      "Button",
      "Card",
      "Link",
    ]);
    expect(result.ucfs.every((ucf) => ucf.props.length === 0)).toBe(true);
    expect(result.ucfs.some((ucf) => ucf.filePath === "src/index.ts")).toBe(false);
    expect(progress.at(-1)).toEqual({
      filesProcessed: Object.keys(files).length,
      totalFiles: Object.keys(files).length,
      componentsFound: result.ucfs.length,
    });
  });

  it("handles wrapper/createElement cases and ignores missing or weak candidates", async () => {
    const files = {
      "src/Input.tsx": [
        "import React from 'react';",
        "export const Input = React.memo(() => React.createElement('input'));",
      ].join("\n"),
      "src/Button.tsx": [
        "function Button() {",
        "  return <button />;",
        "}",
        "export { Button };",
        "export default Button;",
      ].join("\n"),
      "src/avatar.tsx": "export default () => <img alt=\"\" />;",
      "src/helper.ts": "export const Maybe = () => 'not jsx';",
    };

    const result = await extractQuickComponentCandidatesFromSource({
      source: createMemoryScanSource(files),
      files: [
        ...Object.keys(files).map((relPath) => ({ relPath })),
        { relPath: "src/Missing.tsx" },
      ],
      sourceCommit: "sha",
      adapterVersion: "quick-test",
    });

    expect(result.filesProcessed).toBe(5);
    expect(result.ucfs.map((ucf) => ucf.componentName).sort()).toEqual(["Button", "Input"]);
    expect(
      result.ucfs.find((ucf) => ucf.componentName === "Input")?.wrappedBy
    ).toEqual(["memo"]);
    expect(
      result.ucfs.find((ucf) => ucf.componentName === "Button")?.exports
    ).toEqual(
      expect.arrayContaining([
        expect.objectContaining({ exportedAs: "Button" }),
        expect.objectContaining({ exportedAs: "default" }),
      ])
    );
  });
});
