import { describe, expect, it } from 'vitest';
import { renderIndex } from '../src/render.js';
import type { FileMeta } from '../src/scan.js';

const NOW = new Date('2026-05-20T22:30:00Z');

function fixture(): FileMeta[] {
  return [
    {
      relPath: 'about-me.md',
      title: 'About me',
      description: 'Quick bio',
      tags: ['bio'],
      related: [],
      bytes: 100,
      mtimeMs: NOW.getTime(),
    },
    {
      relPath: 'engineering/stack.md',
      title: 'Stack',
      description: 'Languages and frameworks',
      tags: ['engineering'],
      related: [],
      bytes: 200,
      mtimeMs: NOW.getTime(),
    },
    {
      relPath: 'processes/release-flow.md',
      title: 'Release flow',
      description: 'How code reaches prod',
      tags: [],
      related: ['stack', 'missing-slug'],
      bytes: 150,
      mtimeMs: NOW.getTime(),
    },
  ];
}

describe('renderIndex', () => {
  it('starts with the AUTO-GENERATED banner followed by a blank line', () => {
    const { markdown } = renderIndex(fixture(), { generatedAt: NOW });
    expect(
      markdown.startsWith(
        '<!-- AUTO-GENERATED by `zeno knowledge index` — do not edit by hand. -->\n\n',
      ),
    ).toBe(true);
  });

  it('contains the required headings, refresh timestamp, and total line', () => {
    const { markdown } = renderIndex(fixture(), { generatedAt: NOW });
    expect(markdown).toContain('# Knowledge Index');
    expect(markdown).toContain('Last refreshed: 2026-05-20T22:30:00.000Z');
    expect(markdown).toMatch(/Total: 3 files · \d+/);
    expect(markdown).toContain('## Files');
  });

  it('renders the ## By tag section when tags exist, alpha-sorted', () => {
    const { markdown } = renderIndex(fixture(), { generatedAt: NOW });
    expect(markdown).toContain('## By tag');
    const byTagIdx = markdown.indexOf('## By tag');
    const after = markdown.slice(byTagIdx);
    expect(after.indexOf('`bio`')).toBeLessThan(after.indexOf('`engineering`'));
  });

  it('omits the ## By tag section entirely when no file has tags', () => {
    const withoutTags = fixture().map((f) => ({ ...f, tags: [] }));
    const { markdown } = renderIndex(withoutTags, { generatedAt: NOW });
    expect(markdown).not.toContain('## By tag');
  });

  it('renders related: inline under each file and marks unresolved slugs', () => {
    const { markdown, unresolvedRelated } = renderIndex(fixture(), { generatedAt: NOW });
    expect(markdown).toContain('related: stack, missing-slug (⚠ unresolved)');
    expect(unresolvedRelated).toEqual([
      { file: 'processes/release-flow.md', slug: 'missing-slug' },
    ]);
  });

  it('emits the placeholder body when no files are provided', () => {
    const { markdown } = renderIndex([], { generatedAt: NOW });
    expect(markdown).toContain('Total: 0 files · 0 B');
    expect(markdown).toContain('_No knowledge files yet.');
    expect(markdown).not.toContain('## By tag');
  });
});
