#!/usr/bin/env python3
"""
DocumentHumanizer - Detects and removes AI writing indicators from documentation.

This module provides comprehensive detection and transformation of AI-generated
text patterns, making documentation sound more natural and human-written.

Author: Luke Steuber
"""

import re
import argparse
import sys
from pathlib import Path
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass
from concurrent.futures import ThreadPoolExecutor, as_completed
import difflib


@dataclass
class Indicator:
    """Represents a detected AI writing indicator."""
    line: int
    text: str
    confidence: float
    suggestion: str
    pattern_name: str


class DocumentHumanizer:
    """
    Detects and transforms AI writing indicators in documentation.

    Supports 15 different pattern types with confidence-based transformations.
    """

    def __init__(self):
        """Initialize pattern matchers and transformation rules."""
        self._init_patterns()
        self._init_transformations()

    def _init_patterns(self):
        """Initialize regex patterns for detection."""
        # Pattern 1: Em-dashes (>2 per paragraph)
        self.em_dash_pattern = re.compile(r'—')

        # Pattern 2: Corporate jargon
        self.jargon_words = {
            'leverage': 'use',
            'robust': 'reliable',
            'streamline': 'simplify',
            'consolidation': 'combining',
            'strategic': 'planned',
            'roi': 'return on investment',
            'optimal': 'best',
            'synergy': 'collaboration'
        }
        self.jargon_pattern = re.compile(
            r'\b(' + '|'.join(self.jargon_words.keys()) + r')\b',
            re.IGNORECASE
        )

        # Pattern 3: Passive voice
        self.passive_patterns = [
            re.compile(r'\bis\s+\w+ed\b', re.IGNORECASE),
            re.compile(r'\bwas\s+\w+ed\b', re.IGNORECASE),
            re.compile(r'\bhas\s+been\s+\w+ed\b', re.IGNORECASE),
            re.compile(r'\bare\s+\w+ed\b', re.IGNORECASE),
            re.compile(r'\bwere\s+\w+ed\b', re.IGNORECASE),
        ]

        # Pattern 4: Hedge phrases
        self.hedge_phrases = [
            'appears to', 'seems to', 'might be', 'could potentially',
            'may possibly', 'tends to suggest', 'it is possible that',
            'arguably', 'perhaps', 'presumably'
        ]
        self.hedge_pattern = re.compile(
            r'\b(' + '|'.join(re.escape(phrase) for phrase in self.hedge_phrases) + r')\b',
            re.IGNORECASE
        )

        # Pattern 5: Buzzword clusters (multiple in same sentence)
        self.buzzwords = [
            'innovative', 'cutting-edge', 'state-of-the-art', 'revolutionary',
            'paradigm', 'ecosystem', 'scalable', 'enterprise-grade',
            'seamless', 'holistic', 'comprehensive', 'integrated'
        ]
        self.buzzword_pattern = re.compile(
            r'\b(' + '|'.join(self.buzzwords) + r')\b',
            re.IGNORECASE
        )

        # Pattern 6: Transition phrases
        self.transition_phrases = [
            'Additionally', 'Furthermore', 'Moreover', "It's worth noting",
            'It should be noted', 'In addition', 'It is important to note',
            'Notably', 'Of note'
        ]
        self.transition_pattern = re.compile(
            r'^(' + '|'.join(re.escape(phrase) for phrase in self.transition_phrases) + r')[,\s]',
            re.IGNORECASE | re.MULTILINE
        )

        # Pattern 7: Over-structuring (>5 consecutive bullets)
        self.bullet_pattern = re.compile(r'^[\s]*[-*+]\s', re.MULTILINE)

        # Pattern 8: Redundancy detection (simple version)
        # More sophisticated implementation in _detect_redundancy

        # Pattern 9: Success metrics
        self.success_pattern = re.compile(
            r'(✅|☑|✓|success metrics achieved|100% complete|fully implemented)',
            re.IGNORECASE
        )

        # Pattern 10: Stiff construction
        self.stiff_phrases = [
            'This document outlines', 'The system features', 'This section describes',
            'The following provides', 'This document provides', 'The purpose of this',
            'This serves to', 'The aim of this'
        ]
        self.stiff_pattern = re.compile(
            r'\b(' + '|'.join(re.escape(phrase) for phrase in self.stiff_phrases) + r')\b',
            re.IGNORECASE
        )

        # Pattern 11: Acronyms without context
        self.common_acronyms = ['AAC', 'ARIA', 'TTS', 'API', 'SDK', 'CLI', 'GUI']

        # Pattern 12: Excessive dates
        self.date_pattern = re.compile(r'\b\d{4}-\d{2}-\d{2}\b')

        # Pattern 13: Attribution
        self.attribution_pattern = re.compile(
            r'(Made with Claude|Generated by|Claude assisted|AI-generated|'
            r'Created with|Powered by Claude|🤖 Generated)',
            re.IGNORECASE
        )

        # Pattern 14: Plural first person
        self.we_pattern = re.compile(r'\bwe\b', re.IGNORECASE)

        # Pattern 15: Formal metadata
        self.metadata_pattern = re.compile(
            r'^(Status:|Author:|Version:|Last Updated:|Document ID:)',
            re.MULTILINE
        )

    def _init_transformations(self):
        """Initialize transformation rules."""
        self.auto_fix_rules = {
            'em_dash': lambda text: text.replace('—', ' (') + ')' if '—' in text else text,
            'attribution': lambda text: '',
            'success_metrics': lambda text: re.sub(r'[✅☑✓]\s*', '', text),
        }

    def _is_code_block(self, line_num: int, lines: List[str]) -> bool:
        """Check if line is within a code block."""
        in_code = False
        for i, line in enumerate(lines[:line_num]):
            if line.strip().startswith('```'):
                in_code = not in_code
        return in_code

    def _is_url_or_citation(self, text: str) -> bool:
        """Check if text contains URLs or citations."""
        url_pattern = re.compile(r'https?://|www\.|`[^`]+`|\[[^\]]+\]\([^\)]+\)')
        return bool(url_pattern.search(text))

    def _is_protected_path(self, filepath: str) -> bool:
        """Check if file is in protected directory (clinical, specs)."""
        path = Path(filepath)
        protected_dirs = ['clinical', 'specs', 'specifications']
        return any(part in protected_dirs for part in path.parts)

    def _detect_em_dashes(self, lines: List[str]) -> List[Indicator]:
        """Detect excessive em-dash usage (>2 per paragraph)."""
        indicators = []
        paragraph = []
        para_start = 0

        for i, line in enumerate(lines):
            if line.strip() == '':
                if paragraph:
                    para_text = ' '.join(paragraph)
                    count = para_text.count('—')
                    if count > 2:
                        indicators.append(Indicator(
                            line=para_start + 1,
                            text=para_text[:100] + '...' if len(para_text) > 100 else para_text,
                            confidence=min(0.95, 0.7 + (count - 2) * 0.1),
                            suggestion=f"Replace {count} em-dashes with parentheses or colons",
                            pattern_name='em_dashes'
                        ))
                paragraph = []
            else:
                if not paragraph:
                    para_start = i
                paragraph.append(line)

        return indicators

    def _detect_jargon(self, lines: List[str]) -> List[Indicator]:
        """Detect corporate jargon."""
        indicators = []
        for i, line in enumerate(lines):
            if self._is_code_block(i, lines) or self._is_url_or_citation(line):
                continue

            matches = self.jargon_pattern.finditer(line)
            for match in matches:
                word = match.group(1).lower()
                if word in self.jargon_words:
                    indicators.append(Indicator(
                        line=i + 1,
                        text=line.strip(),
                        confidence=0.85,
                        suggestion=f"Replace '{word}' with '{self.jargon_words[word]}'",
                        pattern_name='jargon'
                    ))

        return indicators

    def _detect_passive_voice(self, lines: List[str]) -> List[Indicator]:
        """Detect passive voice constructions."""
        indicators = []
        for i, line in enumerate(lines):
            if self._is_code_block(i, lines) or self._is_url_or_citation(line):
                continue

            for pattern in self.passive_patterns:
                if pattern.search(line):
                    indicators.append(Indicator(
                        line=i + 1,
                        text=line.strip(),
                        confidence=0.75,
                        suggestion="Consider rewriting in active voice",
                        pattern_name='passive_voice'
                    ))
                    break

        return indicators

    def _detect_hedge_phrases(self, lines: List[str]) -> List[Indicator]:
        """Detect hedging language."""
        indicators = []
        for i, line in enumerate(lines):
            if self._is_code_block(i, lines):
                continue

            match = self.hedge_pattern.search(line)
            if match:
                indicators.append(Indicator(
                    line=i + 1,
                    text=line.strip(),
                    confidence=0.80,
                    suggestion=f"Remove hedge phrase '{match.group(1)}' for stronger writing",
                    pattern_name='hedge_phrases'
                ))

        return indicators

    def _detect_buzzword_clusters(self, lines: List[str]) -> List[Indicator]:
        """Detect multiple buzzwords in same sentence."""
        indicators = []
        for i, line in enumerate(lines):
            if self._is_code_block(i, lines):
                continue

            # Split into sentences
            sentences = re.split(r'[.!?]+', line)
            for sentence in sentences:
                matches = self.buzzword_pattern.findall(sentence)
                if len(matches) >= 2:
                    indicators.append(Indicator(
                        line=i + 1,
                        text=sentence.strip(),
                        confidence=0.90,
                        suggestion=f"Remove {len(matches)} buzzwords: {', '.join(matches)}",
                        pattern_name='buzzword_clusters'
                    ))

        return indicators

    def _detect_transition_phrases(self, lines: List[str]) -> List[Indicator]:
        """Detect overused transition phrases."""
        indicators = []
        for i, line in enumerate(lines):
            if self._is_code_block(i, lines):
                continue

            match = self.transition_pattern.search(line)
            if match:
                indicators.append(Indicator(
                    line=i + 1,
                    text=line.strip(),
                    confidence=0.75,
                    suggestion=f"Remove formal transition '{match.group(1)}'",
                    pattern_name='transition_phrases'
                ))

        return indicators

    def _detect_over_structuring(self, lines: List[str]) -> List[Indicator]:
        """Detect excessive bullet points (>5 consecutive)."""
        indicators = []
        bullet_count = 0
        bullet_start = 0

        for i, line in enumerate(lines):
            if self.bullet_pattern.match(line):
                if bullet_count == 0:
                    bullet_start = i
                bullet_count += 1
            else:
                if bullet_count > 5:
                    indicators.append(Indicator(
                        line=bullet_start + 1,
                        text=f"{bullet_count} consecutive bullet points",
                        confidence=0.70,
                        suggestion=f"Break up {bullet_count} bullets into smaller sections or paragraphs",
                        pattern_name='over_structuring'
                    ))
                bullet_count = 0

        # Check last group
        if bullet_count > 5:
            indicators.append(Indicator(
                line=bullet_start + 1,
                text=f"{bullet_count} consecutive bullet points",
                confidence=0.70,
                suggestion=f"Break up {bullet_count} bullets into smaller sections or paragraphs",
                pattern_name='over_structuring'
            ))

        return indicators

    def _detect_redundancy(self, lines: List[str]) -> List[Indicator]:
        """Detect redundant information (simple similarity check)."""
        indicators = []
        # Simple version: look for very similar consecutive lines
        for i in range(len(lines) - 1):
            if len(lines[i].strip()) < 20 or self._is_code_block(i, lines):
                continue

            similarity = difflib.SequenceMatcher(None, lines[i], lines[i + 1]).ratio()
            if similarity > 0.7 and similarity < 1.0:
                indicators.append(Indicator(
                    line=i + 1,
                    text=f"{lines[i].strip()[:50]}...",
                    confidence=0.65,
                    suggestion="Similar content on consecutive lines - possible redundancy",
                    pattern_name='redundancy'
                ))

        return indicators

    def _detect_success_metrics(self, lines: List[str]) -> List[Indicator]:
        """Detect success metric indicators."""
        indicators = []
        for i, line in enumerate(lines):
            if self._is_code_block(i, lines):
                continue

            match = self.success_pattern.search(line)
            if match:
                indicators.append(Indicator(
                    line=i + 1,
                    text=line.strip(),
                    confidence=0.95,
                    suggestion=f"Remove success indicator '{match.group(1)}'",
                    pattern_name='success_metrics'
                ))

        return indicators

    def _detect_stiff_construction(self, lines: List[str]) -> List[Indicator]:
        """Detect stiff, template-like constructions."""
        indicators = []
        for i, line in enumerate(lines):
            if self._is_code_block(i, lines):
                continue

            match = self.stiff_pattern.search(line)
            if match:
                indicators.append(Indicator(
                    line=i + 1,
                    text=line.strip(),
                    confidence=0.80,
                    suggestion=f"Rewrite to remove template phrase '{match.group(1)}'",
                    pattern_name='stiff_construction'
                ))

        return indicators

    def _detect_acronyms_without_context(self, lines: List[str]) -> List[Indicator]:
        """Detect acronyms used without nearby definition."""
        indicators = []
        for i, line in enumerate(lines):
            if self._is_code_block(i, lines):
                continue

            for acronym in self.common_acronyms:
                if re.search(r'\b' + acronym + r'\b', line):
                    # Check surrounding lines for definition
                    context_start = max(0, i - 2)
                    context_end = min(len(lines), i + 3)
                    context = ' '.join(lines[context_start:context_end])

                    # Simple check: is the full form mentioned?
                    if acronym not in context.replace(acronym, ''):
                        indicators.append(Indicator(
                            line=i + 1,
                            text=line.strip(),
                            confidence=0.60,
                            suggestion=f"Define '{acronym}' on first use",
                            pattern_name='acronyms_without_context'
                        ))

        return indicators

    def _detect_excessive_dates(self, lines: List[str]) -> List[Indicator]:
        """Detect excessive specific timestamps."""
        indicators = []
        for i, line in enumerate(lines):
            if self._is_code_block(i, lines):
                continue

            matches = list(self.date_pattern.finditer(line))
            if len(matches) > 0:
                indicators.append(Indicator(
                    line=i + 1,
                    text=line.strip(),
                    confidence=0.70,
                    suggestion=f"Remove or generalize {len(matches)} specific date(s)",
                    pattern_name='excessive_dates'
                ))

        return indicators

    def _detect_attribution(self, lines: List[str]) -> List[Indicator]:
        """Detect AI attribution phrases."""
        indicators = []
        for i, line in enumerate(lines):
            match = self.attribution_pattern.search(line)
            if match:
                indicators.append(Indicator(
                    line=i + 1,
                    text=line.strip(),
                    confidence=0.99,
                    suggestion=f"Remove attribution '{match.group(1)}'",
                    pattern_name='attribution'
                ))

        return indicators

    def _detect_plural_first_person(self, lines: List[str]) -> List[Indicator]:
        """Detect 'we' in solo developer context."""
        indicators = []
        for i, line in enumerate(lines):
            if self._is_code_block(i, lines) or self._is_url_or_citation(line):
                continue

            # Check for "we" but not in quotes
            if self.we_pattern.search(line):
                # Higher confidence if it's in a non-collaborative context
                confidence = 0.85 if 'team' not in line.lower() and 'collaboration' not in line.lower() else 0.60
                indicators.append(Indicator(
                    line=i + 1,
                    text=line.strip(),
                    confidence=confidence,
                    suggestion="Replace 'we' with 'I' (solo developer context)",
                    pattern_name='plural_first_person'
                ))

        return indicators

    def _detect_formal_metadata(self, lines: List[str]) -> List[Indicator]:
        """Detect excessive formal metadata fields."""
        indicators = []
        metadata_count = 0
        metadata_lines = []

        for i, line in enumerate(lines):
            if self.metadata_pattern.search(line):
                metadata_count += 1
                metadata_lines.append(i + 1)

        if metadata_count > 3:
            indicators.append(Indicator(
                line=metadata_lines[0],
                text=f"{metadata_count} metadata fields detected",
                confidence=0.75,
                suggestion=f"Reduce {metadata_count} metadata fields to essential information only",
                pattern_name='formal_metadata'
            ))

        return indicators

    def scan_file(self, filepath: str) -> Dict[str, List[Indicator]]:
        """
        Scan file and return detected indicators with confidence scores.

        Args:
            filepath: Path to file to scan

        Returns:
            Dictionary mapping pattern names to lists of indicators
        """
        path = Path(filepath)
        if not path.exists():
            raise FileNotFoundError(f"File not found: {filepath}")

        if path.suffix not in ['.md', '.html', '.txt']:
            raise ValueError(f"Unsupported file type: {path.suffix}")

        with open(filepath, 'r', encoding='utf-8') as f:
            content = f.read()

        lines = content.split('\n')

        # Run all detection methods
        all_indicators = []
        all_indicators.extend(self._detect_em_dashes(lines))
        all_indicators.extend(self._detect_jargon(lines))
        all_indicators.extend(self._detect_passive_voice(lines))
        all_indicators.extend(self._detect_hedge_phrases(lines))
        all_indicators.extend(self._detect_buzzword_clusters(lines))
        all_indicators.extend(self._detect_transition_phrases(lines))
        all_indicators.extend(self._detect_over_structuring(lines))
        all_indicators.extend(self._detect_redundancy(lines))
        all_indicators.extend(self._detect_success_metrics(lines))
        all_indicators.extend(self._detect_stiff_construction(lines))
        all_indicators.extend(self._detect_acronyms_without_context(lines))
        all_indicators.extend(self._detect_excessive_dates(lines))
        all_indicators.extend(self._detect_attribution(lines))
        all_indicators.extend(self._detect_plural_first_person(lines))
        all_indicators.extend(self._detect_formal_metadata(lines))

        # Group by pattern name
        grouped = {}
        for indicator in all_indicators:
            if indicator.pattern_name not in grouped:
                grouped[indicator.pattern_name] = []
            grouped[indicator.pattern_name].append(indicator)

        return grouped

    def apply_transforms(self, content: str, confidence_threshold: float = 0.8) -> str:
        """
        Apply transformations above confidence threshold.

        Args:
            content: Original content
            confidence_threshold: Minimum confidence to apply transform (0.0-1.0)

        Returns:
            Transformed content
        """
        lines = content.split('\n')
        transformed_lines = lines.copy()

        # Apply high-confidence fixes
        for i, line in enumerate(transformed_lines):
            if self._is_code_block(i, lines) or self._is_url_or_citation(line):
                continue

            # Attribution removal (confidence 0.99)
            if confidence_threshold <= 0.99:
                if self.attribution_pattern.search(line):
                    transformed_lines[i] = self.attribution_pattern.sub('', line)

            # Success metrics removal (confidence 0.95)
            if confidence_threshold <= 0.95:
                if self.success_pattern.search(line):
                    transformed_lines[i] = re.sub(r'[✅☑✓]\s*', '', line)

            # Em-dash replacement (confidence 0.85-0.95)
            if confidence_threshold <= 0.90:
                dash_count = line.count('—')
                if dash_count > 2:
                    # Replace em-dashes with parentheses or colons
                    transformed_lines[i] = line.replace('—', ':')

            # Jargon replacement (confidence 0.85)
            if confidence_threshold <= 0.85:
                for jargon, replacement in self.jargon_words.items():
                    pattern = re.compile(r'\b' + jargon + r'\b', re.IGNORECASE)
                    transformed_lines[i] = pattern.sub(replacement, transformed_lines[i])

            # We -> I replacement (confidence 0.85 in solo context)
            if confidence_threshold <= 0.85:
                if 'team' not in line.lower() and 'collaboration' not in line.lower():
                    transformed_lines[i] = re.sub(r'\bwe\b', 'I', transformed_lines[i])
                    transformed_lines[i] = re.sub(r'\bWe\b', 'I', transformed_lines[i])
                    transformed_lines[i] = re.sub(r'\bour\b', 'my', transformed_lines[i])
                    transformed_lines[i] = re.sub(r'\bOur\b', 'My', transformed_lines[i])

        return '\n'.join(transformed_lines)

    def generate_diff(self, original: str, transformed: str) -> str:
        """
        Generate unified diff for preview.

        Args:
            original: Original content
            transformed: Transformed content

        Returns:
            Unified diff string
        """
        original_lines = original.splitlines(keepends=True)
        transformed_lines = transformed.splitlines(keepends=True)

        diff = difflib.unified_diff(
            original_lines,
            transformed_lines,
            fromfile='original',
            tofile='humanized',
            lineterm='\n'
        )

        return ''.join(diff)

    def batch_process(
        self,
        file_paths: List[str],
        parallel: bool = True,
        max_workers: int = 10
    ) -> Dict[str, Dict[str, List[Indicator]]]:
        """
        Process multiple files in parallel.

        Args:
            file_paths: List of file paths to process
            parallel: Whether to use parallel processing
            max_workers: Maximum number of worker threads

        Returns:
            Dictionary mapping file paths to their scan results
        """
        results = {}

        if parallel and len(file_paths) > 1:
            with ThreadPoolExecutor(max_workers=max_workers) as executor:
                future_to_path = {
                    executor.submit(self.scan_file, path): path
                    for path in file_paths
                }

                for future in as_completed(future_to_path):
                    path = future_to_path[future]
                    try:
                        results[path] = future.result()
                    except Exception as e:
                        results[path] = {'error': [Indicator(
                            line=0,
                            text=str(e),
                            confidence=1.0,
                            suggestion='Fix error before processing',
                            pattern_name='error'
                        )]}
        else:
            for path in file_paths:
                try:
                    results[path] = self.scan_file(path)
                except Exception as e:
                    results[path] = {'error': [Indicator(
                        line=0,
                        text=str(e),
                        confidence=1.0,
                        suggestion='Fix error before processing',
                        pattern_name='error'
                    )]}

        return results


def format_scan_results(results: Dict[str, List[Indicator]]) -> str:
    """Format scan results for display."""
    output = []

    if not results:
        return "✓ No AI writing indicators detected"

    total_indicators = sum(len(indicators) for indicators in results.values())
    output.append(f"\n🔍 Found {total_indicators} AI writing indicators:\n")

    for pattern_name, indicators in sorted(results.items()):
        output.append(f"\n{pattern_name.upper().replace('_', ' ')} ({len(indicators)} occurrences):")
        output.append("=" * 60)

        for indicator in indicators:
            confidence_bar = "█" * int(indicator.confidence * 10)
            output.append(f"\nLine {indicator.line} [{confidence_bar}] {indicator.confidence:.0%} confidence")
            output.append(f"  Text: {indicator.text}")
            output.append(f"  💡 {indicator.suggestion}")

    return '\n'.join(output)


def main():
    """CLI entry point."""
    parser = argparse.ArgumentParser(
        description='Detect and remove AI writing indicators from documentation',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  %(prog)s scan file.md
  %(prog)s scan file.md --threshold 0.7
  %(prog)s fix file.md --confidence 0.8
  %(prog)s diff file.md
  %(prog)s batch file1.md file2.md --parallel
        """
    )

    parser.add_argument(
        'command',
        choices=['scan', 'fix', 'diff', 'batch'],
        help='Command to execute'
    )

    parser.add_argument(
        'files',
        nargs='+',
        help='File(s) to process'
    )

    parser.add_argument(
        '--threshold',
        type=float,
        default=0.7,
        help='Confidence threshold for scan results (0.0-1.0, default: 0.7)'
    )

    parser.add_argument(
        '--confidence',
        type=float,
        default=0.8,
        help='Confidence threshold for applying fixes (0.0-1.0, default: 0.8)'
    )

    parser.add_argument(
        '--parallel',
        action='store_true',
        help='Process files in parallel (batch mode only)'
    )

    parser.add_argument(
        '--max-workers',
        type=int,
        default=10,
        help='Maximum parallel workers (default: 10)'
    )

    parser.add_argument(
        '--dry-run',
        action='store_true',
        help='Preview changes without saving (fix mode only)'
    )

    args = parser.parse_args()

    humanizer = DocumentHumanizer()

    try:
        if args.command == 'scan':
            for filepath in args.files:
                print(f"\n📄 Scanning: {filepath}")
                results = humanizer.scan_file(filepath)

                # Filter by threshold
                filtered = {
                    pattern: [ind for ind in indicators if ind.confidence >= args.threshold]
                    for pattern, indicators in results.items()
                }
                filtered = {k: v for k, v in filtered.items() if v}

                print(format_scan_results(filtered))

        elif args.command == 'fix':
            for filepath in args.files:
                print(f"\n🔧 Fixing: {filepath}")

                with open(filepath, 'r', encoding='utf-8') as f:
                    original = f.read()

                transformed = humanizer.apply_transforms(original, args.confidence)

                if args.dry_run:
                    diff = humanizer.generate_diff(original, transformed)
                    print("\nPreview of changes:")
                    print(diff)
                else:
                    with open(filepath, 'w', encoding='utf-8') as f:
                        f.write(transformed)
                    print(f"✓ Fixed and saved: {filepath}")

        elif args.command == 'diff':
            for filepath in args.files:
                print(f"\n📊 Diff for: {filepath}")

                with open(filepath, 'r', encoding='utf-8') as f:
                    original = f.read()

                transformed = humanizer.apply_transforms(original, args.confidence)
                diff = humanizer.generate_diff(original, transformed)

                if diff:
                    print(diff)
                else:
                    print("✓ No changes would be made")

        elif args.command == 'batch':
            print(f"\n⚙️  Processing {len(args.files)} files...")
            results = humanizer.batch_process(
                args.files,
                parallel=args.parallel,
                max_workers=args.max_workers
            )

            for filepath, file_results in results.items():
                print(f"\n📄 {filepath}:")

                # Filter by threshold
                filtered = {
                    pattern: [ind for ind in indicators if ind.confidence >= args.threshold]
                    for pattern, indicators in file_results.items()
                }
                filtered = {k: v for k, v in filtered.items() if v}

                if filtered:
                    total = sum(len(indicators) for indicators in filtered.values())
                    print(f"  Found {total} indicators")
                else:
                    print("  ✓ Clean")

    except Exception as e:
        print(f"\n❌ Error: {e}", file=sys.stderr)
        return 1

    return 0


if __name__ == '__main__':
    sys.exit(main())
