import { describe, expect, test } from 'bun:test'
import {
  permissionRuleExtractPrefix,
  hasWildcards,
  matchWildcardPattern,
  parsePermissionRule,
  suggestionForExactCommand,
  suggestionForPrefix,
} from '../shellRuleMatching'

// ─── permissionRuleExtractPrefix ────────────────────────────────────────

describe('permissionRuleExtractPrefix', () => {
  test('extracts prefix from legacy :* syntax', () => {
    expect(permissionRuleExtractPrefix('npm:*')).toBe('npm')
  })

  test('extracts multi-word prefix', () => {
    expect(permissionRuleExtractPrefix('git commit:*')).toBe('git commit')
  })

  test('returns null for non-prefix rule', () => {
    expect(permissionRuleExtractPrefix('npm install')).toBeNull()
  })

  test('returns null for empty string', () => {
    expect(permissionRuleExtractPrefix('')).toBeNull()
  })

  test('returns null for wildcard without colon', () => {
    expect(permissionRuleExtractPrefix('npm *')).toBeNull()
  })
})

// ─── hasWildcards ───────────────────────────────────────────────────────

describe('hasWildcards', () => {
  test('returns true for unescaped wildcard', () => {
    expect(hasWildcards('git *')).toBe(true)
  })

  test('returns false for legacy :* syntax', () => {
    expect(hasWildcards('npm:*')).toBe(false)
  })

  test('returns false for escaped wildcard', () => {
    expect(hasWildcards('git \\*')).toBe(false)
  })

  test('returns true for * with even backslashes', () => {
    expect(hasWildcards('git \\\\*')).toBe(true)
  })

  test('returns false for no wildcards', () => {
    expect(hasWildcards('npm install')).toBe(false)
  })

  test('returns false for empty string', () => {
    expect(hasWildcards('')).toBe(false)
  })
})

// ─── matchWildcardPattern ───────────────────────────────────────────────

describe('matchWildcardPattern', () => {
  test('matches simple wildcard', () => {
    expect(matchWildcardPattern('git *', 'git add')).toBe(true)
  })

  test('matches bare command when pattern ends with space-wildcard', () => {
    expect(matchWildcardPattern('git *', 'git')).toBe(true)
  })

  test('rejects non-matching command', () => {
    expect(matchWildcardPattern('git *', 'npm install')).toBe(false)
  })

  test('matches middle wildcard', () => {
    expect(matchWildcardPattern('git * --verbose', 'git add --verbose')).toBe(
      true,
    )
  })

  test('handles escaped asterisk as literal', () => {
    expect(matchWildcardPattern('echo \\*', 'echo *')).toBe(true)
    expect(matchWildcardPattern('echo \\*', 'echo hello')).toBe(false)
  })

  test('case-insensitive matching', () => {
    expect(matchWildcardPattern('Git *', 'git add', true)).toBe(true)
  })

  test('exact match without wildcards', () => {
    expect(matchWildcardPattern('npm install', 'npm install')).toBe(true)
    expect(matchWildcardPattern('npm install', 'npm update')).toBe(false)
  })

  test('handles regex special characters in pattern', () => {
    expect(matchWildcardPattern('echo (hello)', 'echo (hello)')).toBe(true)
  })
})

// ─── parsePermissionRule ────────────────────────────────────────────────

describe('parsePermissionRule', () => {
  test('parses exact command', () => {
    const result = parsePermissionRule('npm install')
    expect(result).toEqual({ type: 'exact', command: 'npm install' })
  })

  test('parses legacy prefix syntax', () => {
    const result = parsePermissionRule('npm:*')
    expect(result).toEqual({ type: 'prefix', prefix: 'npm' })
  })

  test('parses wildcard pattern', () => {
    const result = parsePermissionRule('git *')
    expect(result).toEqual({ type: 'wildcard', pattern: 'git *' })
  })

  test('escaped wildcard is treated as exact', () => {
    const result = parsePermissionRule('echo \\*')
    expect(result.type).toBe('exact')
  })
})

// ─── suggestionForExactCommand ──────────────────────────────────────────

describe('suggestionForExactCommand', () => {
  test('creates addRules suggestion', () => {
    const result = suggestionForExactCommand('Bash', 'npm install')
    expect(result).toHaveLength(1)
    expect(result[0]!.type).toBe('addRules')
    expect((result[0] as any).rules[0]!.toolName).toBe('Bash')
    expect((result[0] as any).rules[0]!.ruleContent).toBe('npm install')
    expect((result[0] as any).behavior).toBe('allow')
  })
})

// ─── suggestionForPrefix ────────────────────────────────────────────────

describe('suggestionForPrefix', () => {
  test('creates prefix suggestion with :*', () => {
    const result = suggestionForPrefix('Bash', 'npm')
    expect((result[0] as any).rules[0]!.ruleContent).toBe('npm:*')
  })
})
