#!/usr/bin/env python3
"""
Script to replace decorative/informational kodo-cyan instances with kodo-steel
for Action 11.3.1.3: Apply 80/20 rule (80% neutral, 20% color)

This script:
1. Finds all instances of kodo-cyan usage
2. Identifies decorative/informational instances
3. Replaces them with kodo-steel variants
4. Preserves active/functional states, design system variants, semantic indicators
"""

import os
import re
import sys
from pathlib import Path
from typing import List, Tuple, Dict

# Patterns to find kodo-cyan usage
CYAN_PATTERNS = [
    r'bg-kodo-cyan/10',
    r'bg-kodo-cyan/20',
    r'border-kodo-cyan/30',
    r'border-kodo-cyan/20',
    r'border-kodo-cyan',
    r'text-kodo-cyan',
    r'text-kodo-cyan-dim',
]

# Patterns that indicate functional/active states (PRESERVE)
PRESERVE_PATTERNS = [
    # Active/selected states - check for conditional logic
    r'\?.*kodo-cyan.*:',
    r':.*kodo-cyan.*\?',
    r'isSelected.*\?.*kodo-cyan',
    r'isActive.*\?.*kodo-cyan',
    r'isCurrent.*\?.*kodo-cyan',
    r'selected.*\?.*kodo-cyan',
    r'active.*\?.*kodo-cyan',
    r'current.*\?.*kodo-cyan',
    r'isPlaying.*\?.*kodo-cyan',
    r'isFocused.*\?.*kodo-cyan',
    r'isMe.*\?.*kodo-cyan',
    r'connected.*\?.*kodo-cyan',
    r'is_current.*\?.*kodo-cyan',
    r'draggedIndex.*\?.*kodo-cyan',
    r'autoScroll.*\?.*kodo-cyan',
    r'showVisualizer.*\?.*kodo-cyan',
    r'isQueueOpen.*\?.*kodo-cyan',
    r'queueTab.*\?.*kodo-cyan',
    r'paymentMethod.*\?.*kodo-cyan',
    r'currentTheme.*\?.*kodo-cyan',
    r'theme ===.*\?.*kodo-cyan',
    r'dateRange ===.*\?.*kodo-cyan',
    # Design system variants (PRESERVE) - exact matches
    r'cyan:\s*[\'"]kodo-cyan',
    r'color:\s*[\'"]cyan',
    r'variant:\s*[\'"]cyan',
    r'variant:\s*[\'"]info',
    r'severity:\s*[\'"]info',
    r'badge.*cyan',
    r'Spinner.*cyan',
    r'default:\s*[\'"]kodo-cyan',
    # Semantic indicators (PRESERVE)
    r'PasswordStrengthIndicator',
    r'isPrivate.*\?.*kodo-cyan',
    r'isPublic.*\?.*kodo-cyan',
    # Functional links (PRESERVE)
    r'hover:underline',
    r'<a\s+.*kodo-cyan',
    r'href=',
    # Progress bars and functional visualizations (PRESERVE)
    r'style=.*width.*kodo-cyan',
    r'progress',
    # Button variants (PRESERVE)
    r'variant=.*primary',
    r'variant=.*default',
    # Test files (PRESERVE)
    r'\.test\.',
    r'\.spec\.',
]

# Files/directories to skip
SKIP_PATTERNS = [
    'node_modules',
    '.git',
    '.build',
    'dist',
    'coverage',
    'test-reports',
    'EXHAUSTIVE_TODO_LIST.md',
    'HOVER_EFFECTS_AUDIT.md',
    'COLOR_USAGE.md',
    'COMPONENT_USAGE.md',
]

# Replacement mappings
REPLACEMENTS = {
    'bg-kodo-cyan/10': 'bg-kodo-steel/10',
    'bg-kodo-cyan/20': 'bg-kodo-steel/20',
    'border-kodo-cyan/30': 'border-kodo-steel/30',
    'border-kodo-cyan/20': 'border-kodo-steel/20',
    'border-kodo-cyan': 'border-kodo-steel',
    'text-kodo-cyan': 'text-kodo-steel',
    'text-kodo-cyan-dim': 'text-kodo-steel',
    'border-t-kodo-cyan': 'border-t-kodo-steel',
    'ring-kodo-cyan': 'ring-kodo-steel',
    'shadow-kodo-cyan': 'shadow-kodo-steel',
}

def should_preserve(line: str, file_path: str, context_lines: List[str] = None) -> bool:
    """Check if this line should be preserved (functional/active state)"""
    # Skip test and documentation files
    if any(pattern in file_path for pattern in SKIP_PATTERNS):
        return True
    
    # Check preserve patterns in current line
    for pattern in PRESERVE_PATTERNS:
        if re.search(pattern, line, re.IGNORECASE):
            return True
    
    # Check context (previous and next lines) for conditional logic
    if context_lines:
        context = ' '.join(context_lines)
        # If cyan appears in a ternary or conditional, preserve it
        if re.search(r'\?.*kodo-cyan|kodo-cyan.*\?', context, re.IGNORECASE):
            return True
        # If it's part of a variant/color prop, preserve it
        if re.search(r'(variant|color|severity).*:.*cyan', context, re.IGNORECASE):
            return True
    
    # Check if line contains conditional logic with cyan
    if re.search(r'\?.*kodo-cyan|kodo-cyan.*\?', line, re.IGNORECASE):
        return True
    
    # Check if it's a design system prop
    if re.search(r'(variant|color|severity)\s*[:=]\s*[\'"]?(cyan|info)', line, re.IGNORECASE):
        return True
    
    return False

def find_cyan_instances(file_path: Path) -> List[Tuple[int, str, str]]:
    """Find all kodo-cyan instances in a file"""
    instances = []
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            lines = f.readlines()
            for line_num, line in enumerate(lines, 1):
                for pattern in CYAN_PATTERNS:
                    if re.search(pattern, line):
                        instances.append((line_num, line, pattern))
                        break
    except Exception as e:
        print(f"Error reading {file_path}: {e}", file=sys.stderr)
    return instances

def replace_decorative_cyan(file_path: Path, dry_run: bool = False) -> Tuple[int, int]:
    """Replace decorative cyan instances in a file"""
    replaced = 0
    preserved = 0
    
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
            original_content = content
        
        lines = content.split('\n')
        new_lines = []
        
        for line_num, line in enumerate(lines, 1):
            original_line = line
            
            # Get context (previous 2 and next 2 lines)
            context_start = max(0, line_num - 3)
            context_end = min(len(lines), line_num + 2)
            context_lines = lines[context_start:context_end]
            
            # Check if should preserve
            if should_preserve(line, str(file_path), context_lines):
                # Count preserved instances
                for pattern in CYAN_PATTERNS:
                    if re.search(pattern, line, re.IGNORECASE):
                        preserved += 1
                        break
                new_lines.append(line)
                continue
            
            # Replace decorative instances
            line_replaced = False
            for old, new in REPLACEMENTS.items():
                if old in line:
                    # Double-check we shouldn't preserve
                    if not should_preserve(line, str(file_path), context_lines):
                        line = line.replace(old, new)
                        if not line_replaced:
                            replaced += 1
                            line_replaced = True
            
            new_lines.append(line)
        
        new_content = '\n'.join(new_lines)
        
        if not dry_run and new_content != original_content:
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(new_content)
        
        return replaced, preserved
    
    except Exception as e:
        print(f"Error processing {file_path}: {e}", file=sys.stderr)
        return 0, 0

def main():
    """Main function"""
    import argparse
    
    parser = argparse.ArgumentParser(description='Replace decorative kodo-cyan with kodo-steel')
    parser.add_argument('--dry-run', action='store_true', help='Show what would be changed without making changes')
    parser.add_argument('--path', default='apps/web/src', help='Path to search (default: apps/web/src)')
    args = parser.parse_args()
    
    base_path = Path(args.path)
    if not base_path.exists():
        print(f"Error: Path {base_path} does not exist", file=sys.stderr)
        sys.exit(1)
    
    # Find all TypeScript/TSX files
    tsx_files = []
    for ext in ['*.tsx', '*.ts']:
        tsx_files.extend(base_path.rglob(ext))
    
    # Filter out skipped files
    files_to_process = []
    for file_path in tsx_files:
        if not any(pattern in str(file_path) for pattern in SKIP_PATTERNS):
            files_to_process.append(file_path)
    
    print(f"Found {len(files_to_process)} files to process")
    if args.dry_run:
        print("DRY RUN MODE - No files will be modified\n")
    
    total_replaced = 0
    total_preserved = 0
    files_modified = []
    
    for file_path in sorted(files_to_process):
        replaced, preserved = replace_decorative_cyan(file_path, dry_run=args.dry_run)
        if replaced > 0:
            total_replaced += replaced
            total_preserved += preserved
            files_modified.append((file_path, replaced, preserved))
            status = "[DRY RUN] Would modify" if args.dry_run else "Modified"
            print(f"{status}: {file_path} ({replaced} replaced, {preserved} preserved)")
    
    print(f"\n{'='*60}")
    print(f"Total files {'would be ' if args.dry_run else ''}modified: {len(files_modified)}")
    print(f"Total instances replaced: {total_replaced}")
    print(f"Total instances preserved: {total_preserved}")
    print(f"{'='*60}")
    
    if args.dry_run and len(files_modified) > 0:
        print("\nRun without --dry-run to apply changes")

if __name__ == '__main__':
    main()
