import { describe, expect, test } from "bun:test";
import { formatWrn, parse } from "../src/index.ts";

const options = {
  insertSpaces: true,
  tabSize: 2,
  printWidth: 70,
  multilineAttributes: true,
} as const;

describe("canonical WRN formatter", () => {
  test("formats declarations, structured values, markup, and imports idempotently", () => {
    const source = `import Card from "@/components/Card.wrn"
component Demo {
props { title: string = "Hello" items = [{ id: 1, label: "One" }] }
view {
<Card title='{title}' items='{items}' class="very-long-utility-name another-long-utility-name"><strong>{title}</strong></Card>
}
}`;
    const formatted = formatWrn(source, options);

    expect(formatted).toContain('import Card from "@/components/Card.wrn"');
    expect(formatted).toContain('props {\n    title: string = "Hello"');
    expect(formatted).toContain('items = [{ id: 1, label: "One" }]');
    expect(formatted).toContain("<Card\n");
    expect(formatWrn(formatted, options)).toBe(formatted);
    expect(() => parse(formatted)).not.toThrow();
  });

  test("preserves comments and normalizes the final newline", () => {
    const source = `// leading comment\r\npage Home {\r\nview { <!-- keep --> <p>Home</p> }\r\n}`;
    const formatted = formatWrn(source, options);

    expect(formatted.startsWith("// leading comment\n")).toBe(true);
    expect(formatted).toContain("<!-- keep -->");
    expect(formatted.endsWith("\n")).toBe(true);
    expect(formatted).not.toContain("\r");
  });
});

test("preserves preformatted code examples while formatting surrounding markup", () => {
  const source = `page Docs {
  view {
    <section class="docs">
      <pre><code><span class="code-muted">// One project, one language</span>
<span class="code-key">page</span> ProductDashboard {
  <span class="code-key">state</span> count: number = 0
  &lt;button @click='count++'&gt;Ship {count}&lt;/button&gt;
}</code></pre>
    </section>
  }
}
`;
  const formatted = formatWrn(source, options);
  expect(formatted)
    .toContain(`<pre><code><span class="code-muted">// One project, one language</span>
<span class="code-key">page</span> ProductDashboard {
  <span class="code-key">state</span> count: number = 0`);
  expect(formatWrn(formatted, options)).toBe(formatted);
  expect(() => parse(formatted)).not.toThrow();
});

test("does not split an attribute-free opening tag delimiter", () => {
  const source = `page Docs {
  view {
    <p>This is intentionally long documentation copy that should wrap as content without formatting the opening p tag as separate less-than and greater-than lines.</p>
  }
}
`;
  const formatted = formatWrn(source, options);
  expect(formatted).toContain("    <p>\n");
  expect(formatted).not.toContain("    <p\n    >");
  expect(formatWrn(formatted, options)).toBe(formatted);
});

test("preserves balanced compact sibling markup without indentation drift", () => {
  const source = `page Compact {
  view {
    <div class="strip"><span>Page</span><b>→</b><span>API</span></div>
  }
}\n`;
  const formatted = formatWrn(source, { tabSize: 2, printWidth: 80 });
  expect(formatted).toContain('<div class="strip"><span>Page</span><b>→</b><span>API</span></div>');
  expect(formatWrn(formatted, { tabSize: 2, printWidth: 80 })).toBe(formatted);
});
