class Clacky::GitignoreParser

Parser for .gitignore files to determine which files should be ignored

def ignored?(path)

Check if a file path should be ignored
def ignored?(path)
  relative_path = path.start_with?('./') ? path[2..] : path
  
  # Check negation patterns first (! prefix in .gitignore)
  @negation_patterns.each do |pattern|
    return false if match_pattern?(relative_path, pattern)
  end
  
  # Then check ignore patterns
  @patterns.each do |pattern|
    return true if match_pattern?(relative_path, pattern)
  end
  
  false
end

def initialize(gitignore_path = nil)

def initialize(gitignore_path = nil)
  @patterns = []
  @negation_patterns = []
  
  if gitignore_path && File.exist?(gitignore_path)
    parse_gitignore(gitignore_path)
  end
end

def match_pattern?(path, pattern_info)

def match_pattern?(path, pattern_info)
  pattern = pattern_info[:pattern]
  is_absolute = pattern_info[:is_absolute]
  
  # For absolute patterns (starting with /), remove the leading slash
  # These patterns match from the root of the repository
  if is_absolute
    pattern = pattern[1..]
    # Absolute patterns match exactly from the start of the path
    return true if path == pattern
    return true if path.start_with?("#{pattern}/")
  end
  
  # Handle directory patterns
  if pattern_info[:is_directory]
    # Directory patterns should match the directory and all its contents
    return true if path == pattern
    return true if path.start_with?("#{pattern}/")
    # Also check if any path component matches the directory pattern
    return true if path.split('/').include?(pattern)
  end
  
  # Handle different wildcard patterns
  if pattern_info[:has_double_star]
    # Convert ** to match any number of directories
    regex_pattern = Regexp.escape(pattern)
      .gsub('\*\*/', '(.*/)?')  # **/ matches zero or more directories
      .gsub('\*\*', '.*')        # ** at end matches anything
      .gsub('\*', '[^/]*')       # * matches anything except /
      .gsub('\?', '[^/]')        # ? matches single character except /
    
    regex = Regexp.new("^#{regex_pattern}$")
    return true if path.match?(regex)
    return true if path.split('/').any? { |part| part.match?(regex) }
  elsif pattern_info[:has_wildcard]
    # Convert glob pattern to regex
    regex_pattern = Regexp.escape(pattern)
      .gsub('\*', '[^/]*')
      .gsub('\?', '[^/]')
    
    regex = Regexp.new("^#{regex_pattern}$")
    return true if path.match?(regex)
    return true if File.basename(path).match?(regex)
  else
    # Exact match - pattern without wildcards
    # Match as basename or as path prefix
    return true if path == pattern
    return true if path.start_with?("#{pattern}/")
    return true if File.basename(path) == pattern
    # Also check if pattern matches any path component
    return true if path.split('/').include?(pattern)
  end
  
  false
end

def normalize_pattern(pattern)

def normalize_pattern(pattern)
  pattern = pattern.strip
  
  # Remove trailing whitespace
  pattern = pattern.rstrip
  
  # Store original for directory detection
  is_directory = pattern.end_with?('/')
  pattern = pattern.chomp('/')
  
  {
    pattern: pattern,
    is_directory: is_directory,
    is_absolute: pattern.start_with?('/'),
    has_wildcard: pattern.include?('*') || pattern.include?('?'),
    has_double_star: pattern.include?('**')
  }
end

def parse_gitignore(path)

def parse_gitignore(path)
  File.readlines(path, chomp: true).each do |line|
    # Skip comments and empty lines
    next if line.strip.empty? || line.start_with?('#')
    
    # Handle negation patterns (lines starting with !)
    if line.start_with?('!')
      @negation_patterns << normalize_pattern(line[1..])
    else
      @patterns << normalize_pattern(line)
    end
  end
rescue StandardError => e
  # If we can't parse .gitignore, just continue with empty patterns
  warn "Warning: Failed to parse .gitignore: #{e.message}"
end