import { describe, expect, test } from 'bun:test';
import { homedir } from 'node:os';
import { analyzeCommand } from '../src/core/analyze.ts';
import type { Config } from '../src/types.ts';

const EMPTY_CONFIG: Config = { version: 1, rules: [] };

describe('analyzeCommand (coverage)', () => {
  test('unclosed-quote cd segment handled', () => {
    // Ensures cwd-tracking fallback runs for unparseable cd segments.
    expect(
      analyzeCommand('cd "unterminated', {
        cwd: '/tmp',
        config: EMPTY_CONFIG,
      }),
    ).toBeNull();
  });

  test('empty head token returns null', () => {
    expect(
      analyzeCommand('""', {
        cwd: '/tmp',
        config: EMPTY_CONFIG,
      }),
    ).toBeNull();
  });

  test('rm -rf in home cwd is blocked with dedicated message', () => {
    const result = analyzeCommand('rm -rf build', {
      cwd: homedir(),
      config: EMPTY_CONFIG,
    });
    expect(result?.reason).toContain('rm -rf in home directory');
  });

  test('rm without -rf in home cwd is not blocked by home cwd guard', () => {
    expect(
      analyzeCommand('rm -f file.txt', {
        cwd: homedir(),
        config: EMPTY_CONFIG,
      }),
    ).toBeNull();
  });

  test('custom rules can block rm after builtin allow', () => {
    const config: Config = {
      version: 1,
      rules: [
        {
          name: 'block-rm-rf',
          command: 'rm',
          block_args: ['-rf'],
          reason: 'No rm -rf.',
        },
      ],
    };
    const result = analyzeCommand('rm -rf /tmp/test-dir', {
      cwd: '/tmp',
      config,
    });
    expect(result?.reason).toContain('[block-rm-rf] No rm -rf.');
  });

  test('custom rules can block find after builtin allow', () => {
    const config: Config = {
      version: 1,
      rules: [
        {
          name: 'block-find-print',
          command: 'find',
          block_args: ['-print'],
          reason: 'Avoid find -print in tests.',
        },
      ],
    };
    const result = analyzeCommand('find . -print', { cwd: '/tmp', config });
    expect(result?.reason).toContain('[block-find-print] Avoid find -print in tests.');
  });

  test('fallback scan catches embedded rm', () => {
    const result = analyzeCommand('tool rm -rf /', {
      cwd: '/tmp',
      config: EMPTY_CONFIG,
    });
    expect(result?.reason).toContain('extremely dangerous');
  });

  test('fallback scan ignores embedded rm when analyzeRm allows it', () => {
    expect(
      analyzeCommand('tool rm -rf /tmp/a', {
        cwd: '/tmp',
        config: EMPTY_CONFIG,
      }),
    ).toBeNull();
  });

  test('fallback scan catches embedded git', () => {
    const result = analyzeCommand('tool git reset --hard', {
      cwd: '/tmp',
      config: EMPTY_CONFIG,
    });
    expect(result?.reason).toContain('git reset --hard');
  });

  test('fallback scan ignores embedded git when safe', () => {
    expect(
      analyzeCommand('tool git status', {
        cwd: '/tmp',
        config: EMPTY_CONFIG,
      }),
    ).toBeNull();
  });

  test('fallback scan catches embedded find', () => {
    const result = analyzeCommand('tool find . -delete', {
      cwd: '/tmp',
      config: EMPTY_CONFIG,
    });
    expect(result?.reason).toContain('find -delete');
  });

  test('fallback scan ignores embedded find when safe', () => {
    expect(
      analyzeCommand('tool find . -print', {
        cwd: '/tmp',
        config: EMPTY_CONFIG,
      }),
    ).toBeNull();
  });

  test('TMPDIR override to a temp dir keeps $TMPDIR allowed', () => {
    const result = analyzeCommand('TMPDIR=/tmp rm -rf $TMPDIR/test-dir', {
      cwd: '/tmp',
      config: EMPTY_CONFIG,
    });
    expect(result).toBeNull();
  });

  test('xargs child git command is analyzed', () => {
    const result = analyzeCommand('xargs git reset --hard', {
      cwd: '/tmp',
      config: EMPTY_CONFIG,
    });
    expect(result?.reason).toContain('git reset --hard');
  });

  test('xargs child git command can be safe', () => {
    expect(
      analyzeCommand('xargs git status', {
        cwd: '/tmp',
        config: EMPTY_CONFIG,
      }),
    ).toBeNull();
  });

  describe('parallel parsing/analysis branches', () => {
    test('parallel bash -c with placeholder and no args analyzes template', () => {
      const result = analyzeCommand("parallel bash -c 'echo {}'", {
        cwd: '/tmp',
        config: EMPTY_CONFIG,
      });
      expect(result).toBeNull();
    });

    test('parallel bash -c with placeholder outside script is blocked', () => {
      const result = analyzeCommand("parallel bash -c 'echo hi' {} ::: a", {
        cwd: '/tmp',
        config: EMPTY_CONFIG,
      });
      expect(result?.reason).toContain('parallel with shell -c');
    });

    test('parallel bash -c without script but with args is blocked', () => {
      const result = analyzeCommand("parallel bash -c ::: 'echo hi'", {
        cwd: '/tmp',
        config: EMPTY_CONFIG,
      });
      expect(result?.reason).toContain('parallel with shell -c');
    });

    test('parallel bash -c without script or args is allowed', () => {
      expect(
        analyzeCommand('parallel bash -c', {
          cwd: '/tmp',
          config: EMPTY_CONFIG,
        }),
      ).toBeNull();
    });

    test('parallel bash with placeholder but missing -c arg is blocked', () => {
      const result = analyzeCommand('parallel bash {} -c', {
        cwd: '/tmp',
        config: EMPTY_CONFIG,
      });
      expect(result?.reason).toContain('parallel with shell -c');
    });

    test('parallel rm -rf with explicit temp arg is allowed', () => {
      const result = analyzeCommand('parallel rm -rf ::: /tmp/a', {
        cwd: '/tmp',
        config: EMPTY_CONFIG,
      });
      expect(result).toBeNull();
    });

    test('parallel git tokens are analyzed', () => {
      const result = analyzeCommand('parallel git reset --hard :::', {
        cwd: '/tmp',
        config: EMPTY_CONFIG,
      });
      expect(result?.reason).toContain('git reset --hard');
    });

    test('parallel with -- separator parses template', () => {
      const result = analyzeCommand('parallel -- rm -rf ::: /tmp/a', {
        cwd: '/tmp',
        config: EMPTY_CONFIG,
      });
      expect(result).toBeNull();
    });

    test('parallel -j option consumes its value', () => {
      const result = analyzeCommand('parallel -j 4 rm -rf ::: /tmp/a', {
        cwd: '/tmp',
        config: EMPTY_CONFIG,
      });
      expect(result).toBeNull();
    });
  });
});
