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

import { parseChecklist, summarize } from '../../scripts/lib/checklist-parser.mjs';

interface ChecklistItem {
  checked: boolean;
  text: string;
  naReason?: string;
}

describe('parseChecklist', () => {
  it('returns zero items for empty body', () => {
    const result = parseChecklist('');
    expect(result.items).toEqual([]);
    expect(result.totalUnchecked).toBe(0);
  });

  it('counts every checked item as satisfied', () => {
    const body = `## Checklist
- [x] First item
- [x] Second item
- [X] Third item with capital X`;
    const result = parseChecklist(body);
    expect(result.items).toHaveLength(3);
    expect(result.totalUnchecked).toBe(0);
    expect(result.items.every((i: ChecklistItem) => i.checked)).toBe(true);
  });

  it('counts every unchecked non-N/A item as needing action', () => {
    const body = `- [ ] Tests added
- [ ] Matrix updated
- [x] No new dependencies`;
    const result = parseChecklist(body);
    expect(result.items).toHaveLength(3);
    expect(result.totalUnchecked).toBe(2);
  });

  it('requires N/A items to be checked with a reason', () => {
    const body = `- [ ] Tests added
- [ ] N/A: documentation-only change
- [ ] (N/A) no behaviour change
- [ ] Manual smoke updated`;
    const result = parseChecklist(body);
    expect(result.items).toHaveLength(4);
    expect(result.totalUnchecked).toBe(4);
    expect(result.items[1].naReason).toBe('documentation-only change');
    expect(result.items[2].naReason).toBe('no behaviour change');
    expect(summarize(result)).toContain('N/A items must still be checked with a reason');
  });

  it('treats checked N/A items as satisfied', () => {
    const body = `- [x] Tests added
- [x] N/A: documentation-only change
- [x] (N/A) no behaviour change`;
    const result = parseChecklist(body);
    expect(result.items).toHaveLength(3);
    expect(result.totalUnchecked).toBe(0);
    expect(result.items[1].naReason).toBe('documentation-only change');
    expect(result.items[2].naReason).toBe('no behaviour change');
  });

  it('handles mixed-case [x] and [X] uniformly', () => {
    const body = `- [x] lowercase
- [X] uppercase
- [ ] unchecked`;
    const result = parseChecklist(body);
    expect(result.items.map((i: ChecklistItem) => i.checked)).toEqual([true, true, false]);
    const summary = summarize(result);
    expect(summary).toContain('2/3 items satisfied');
  });

  it('skips checklist markers inside fenced code blocks', () => {
    const body = `- [x] Real checked item
\`\`\`
- [ ] This is a code-block example, not a real checklist item
- [ ] Another decoy in the fence
\`\`\`
- [ ] Real unchecked item`;
    const result = parseChecklist(body);
    expect(result.items).toHaveLength(2);
    expect(result.items[0].text).toBe('Real checked item');
    expect(result.items[1].text).toBe('Real unchecked item');
    expect(result.totalUnchecked).toBe(1);
  });
});
