import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
import { resolve } from 'node:path';

const execFileAsync = promisify(execFile);
const HOOK_PATH = resolve(import.meta.dirname, '../../hooks/scripts/post-edit-verify.mjs');

/**
 * Run the hook with given stdin input (string).
 * Short timeout — these tests should only exercise fast paths.
 */
async function runHook(inputStr, timeout = 10000) {
  try {
    const { stdout } = await execFileAsync('node', [HOOK_PATH], {
      input: inputStr,
      timeout,
    });
    return JSON.parse(stdout || '{}');
  } catch (err) {
    if (err.stdout) {
      try { return JSON.parse(err.stdout); } catch { /* ignore */ }
    }
    return {};
  }
}

// ========================================
// post-edit-verify hook — fast-path tests
// Tests exercise the early-exit paths (non-config, missing file, invalid input).
// Scanner execution paths are covered by scanner tests.
// ========================================
describe('post-edit-verify hook', () => {
  it('returns {} for non-config files', async () => {
    const result = await runHook(JSON.stringify({ file_path: '/tmp/some-random-file.js' }));
    assert.deepEqual(result, {});
  });

  it('returns {} for nonexistent config files', async () => {
    const result = await runHook(JSON.stringify({ file_path: '/nonexistent/CLAUDE.md' }));
    assert.deepEqual(result, {});
  });

  it('returns {} for empty input object', async () => {
    const result = await runHook(JSON.stringify({}));
    assert.deepEqual(result, {});
  });

  it('returns {} for null file_path', async () => {
    const result = await runHook(JSON.stringify({ file_path: null }));
    assert.deepEqual(result, {});
  });

  it('handles invalid JSON gracefully', async () => {
    const result = await runHook('not json at all');
    assert.deepEqual(result, {});
  });

  it('handles empty stdin gracefully', async () => {
    const result = await runHook('');
    assert.deepEqual(result, {});
  });

  it('exits quickly for non-config files', async () => {
    const start = Date.now();
    await runHook(JSON.stringify({ file_path: '/tmp/nothing.txt' }));
    const elapsed = Date.now() - start;
    // Non-config files exit before any scanner import — should be fast
    assert.ok(elapsed < 5000, `Hook took ${elapsed}ms for non-config file`);
  });

  it('has correct shebang and is valid Node.js', async () => {
    const { readFile } = await import('node:fs/promises');
    const content = await readFile(HOOK_PATH, 'utf-8');
    assert.ok(content.startsWith('#!/usr/bin/env node'));
    assert.ok(content.includes('readFileSync'));
    assert.ok(content.includes('detectScanner'));
  });

  it('uses cross-platform rules dir pattern (handles both / and \\)', async () => {
    const { readFile } = await import('node:fs/promises');
    const content = await readFile(HOOK_PATH, 'utf-8');
    // The regex should handle both Unix / and Windows \\ separators
    assert.ok(content.includes('[/\\\\]rules[/\\\\]'), 'RULES_DIR_PATTERN should match both / and \\\\');
  });
});
