// git-clone-gitattributes.test.mjs — Tests for E12 .gitattributes filter-driver advisory
// Pure-function tests for scanGitAttributes(); the CLI path is exercised
// indirectly via the existing git-clone-sandbox.test.mjs suite.

import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync, writeFileSync, rmSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir } from 'node:os';

const { scanGitAttributes } = await import('../../scanners/lib/git-clone.mjs');

function makeRepo(contents) {
  const dir = mkdtempSync(join(tmpdir(), 'gitattr-test-'));
  if (contents !== null) {
    writeFileSync(join(dir, '.gitattributes'), contents);
  }
  return dir;
}

describe('scanGitAttributes', () => {
  it('flags filter driver directive (LFS-style)', () => {
    const dir = makeRepo('*.txt filter=lfs diff=lfs merge=lfs -text\n');
    try {
      const warnings = scanGitAttributes(dir);
      const kinds = warnings.map(w => w.kind).sort();
      assert.deepEqual(kinds, ['diff', 'filter', 'merge']);
      assert.equal(warnings[0].driver, 'lfs');
      assert.equal(warnings[0].line, 1);
      assert.ok(warnings[0].raw.includes('filter=lfs'));
    } finally {
      rmSync(dir, { recursive: true, force: true });
    }
  });

  it('flags custom filter driver', () => {
    const dir = makeRepo('secrets.* filter=encrypt diff=encrypt\n');
    try {
      const warnings = scanGitAttributes(dir);
      assert.equal(warnings.length, 2);
      assert.ok(warnings.find(w => w.kind === 'filter' && w.driver === 'encrypt'));
      assert.ok(warnings.find(w => w.kind === 'diff' && w.driver === 'encrypt'));
    } finally {
      rmSync(dir, { recursive: true, force: true });
    }
  });

  it('returns empty array when .gitattributes is absent', () => {
    const dir = makeRepo(null);
    try {
      const warnings = scanGitAttributes(dir);
      assert.deepEqual(warnings, []);
    } finally {
      rmSync(dir, { recursive: true, force: true });
    }
  });

  it('returns empty array on empty .gitattributes', () => {
    const dir = makeRepo('');
    try {
      assert.deepEqual(scanGitAttributes(dir), []);
    } finally {
      rmSync(dir, { recursive: true, force: true });
    }
  });

  it('returns empty array when only blank lines and comments', () => {
    const dir = makeRepo('# comment line\n\n# filter=trap inside comment\n  \n');
    try {
      assert.deepEqual(scanGitAttributes(dir), []);
    } finally {
      rmSync(dir, { recursive: true, force: true });
    }
  });

  it('ignores trailing inline comments after stripping', () => {
    const dir = makeRepo('*.bin -text  # filter=trap (this is a comment)\n');
    try {
      assert.deepEqual(scanGitAttributes(dir), []);
    } finally {
      rmSync(dir, { recursive: true, force: true });
    }
  });

  it('reports correct line numbers across multi-line files', () => {
    const dir = makeRepo([
      '# hardening',
      '* -text',
      '',
      '*.lfs filter=lfs',
      'docs/* diff=astextplain',
    ].join('\n') + '\n');
    try {
      const warnings = scanGitAttributes(dir);
      const filter = warnings.find(w => w.kind === 'filter');
      const diff = warnings.find(w => w.kind === 'diff');
      assert.equal(filter.line, 4);
      assert.equal(filter.driver, 'lfs');
      assert.equal(diff.line, 5);
      assert.equal(diff.driver, 'astextplain');
    } finally {
      rmSync(dir, { recursive: true, force: true });
    }
  });

  it('handles unreadable .gitattributes by returning empty array', () => {
    // Pass a path that exists as file (not directory) so existsSync says yes
    // but join(path, '.gitattributes') is invalid — emulates a read error
    // gracefully by passing a non-directory location.
    const result = scanGitAttributes('/does/not/exist/at/all');
    assert.deepEqual(result, []);
  });
});
