#!/usr/bin/env python3
"""
Smart Auto-Commit Hook
Generates meaningful commit messages from git diff using AI analysis
"""
import subprocess
import json
import sys
import os
import re
from datetime import datetime

def run_command(cmd):
    """Run shell command and return output"""
    try:
        result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
        return result.stdout.strip(), result.stderr.strip(), result.returncode
    except Exception as e:
        return "", str(e), 1

def has_git_changes():
    """Check if there are uncommitted changes"""
    stdout, _, code = run_command("git status --porcelain")
    return code == 0 and stdout.strip() != ""

def get_git_diff():
    """Get git diff for staged and unstaged changes"""
    # Stage all changes first
    run_command("git add .")
    
    # Get diff
    stdout, _, _ = run_command("git diff --cached --stat")
    diff_stat = stdout
    
    stdout, _, _ = run_command("git diff --cached --name-only")
    changed_files = stdout.split('\n') if stdout else []
    
    return diff_stat, changed_files

def analyze_changes(diff_stat, changed_files):
    """Analyze changes and generate commit message"""
    if not changed_files or changed_files == ['']:
        return None
    
    # Count file types
    file_types = {}
    for file in changed_files:
        if not file:
            continue
        ext = os.path.splitext(file)[1].lower()
        if ext:
            file_types[ext] = file_types.get(ext, 0) + 1
    
    # Determine commit type
    commit_type = "feat"
    if any(f.endswith('.md') for f in changed_files):
        commit_type = "docs"
    elif any(f.endswith(('.test.js', '.spec.js', '.test.py', '.spec.py')) for f in changed_files):
        commit_type = "test"
    elif any(f.endswith(('.json', '.yml', '.yaml', '.toml')) for f in changed_files):
        commit_type = "config"
    elif any('fix' in f.lower() or 'bug' in f.lower() for f in changed_files):
        commit_type = "fix"
    
    # Generate description
    if len(changed_files) == 1:
        file_name = os.path.basename(changed_files[0])
        description = f"update {file_name}"
    elif len(changed_files) <= 3:
        files = [os.path.basename(f) for f in changed_files]
        description = f"update {', '.join(files)}"
    else:
        main_type = max(file_types.items(), key=lambda x: x[1])[0] if file_types else ""
        description = f"update {len(changed_files)} files"
        if main_type:
            description += f" ({main_type} changes)"
    
    return f"{commit_type}: {description}"

def should_auto_commit():
    """Check if we should auto-commit based on file types and size"""
    stdout, _, _ = run_command("git diff --cached --numstat")
    if not stdout:
        return False
    
    lines = stdout.strip().split('\n')
    total_additions = 0
    total_deletions = 0
    
    for line in lines:
        parts = line.split('\t')
        if len(parts) >= 2:
            try:
                additions = int(parts[0]) if parts[0] != '-' else 0
                deletions = int(parts[1]) if parts[1] != '-' else 0
                total_additions += additions
                total_deletions += deletions
            except ValueError:
                continue
    
    # Don't auto-commit huge changes
    if total_additions + total_deletions > 500:
        print(f"⚠️ Large changeset ({total_additions}+, {total_deletions}-) - skipping auto-commit")
        return False
    
    return True

def main():
    try:
        # Check if we're in a git repo
        stdout, _, code = run_command("git rev-parse --git-dir")
        if code != 0:
            sys.exit(0)  # Not a git repo, skip silently
        
        # Check for changes
        if not has_git_changes():
            sys.exit(0)  # No changes, skip
        
        # Get diff info
        diff_stat, changed_files = get_git_diff()
        
        if not should_auto_commit():
            sys.exit(0)
        
        # Generate commit message
        commit_msg = analyze_changes(diff_stat, changed_files)
        if not commit_msg:
            sys.exit(0)
        
        # Add timestamp for uniqueness
        timestamp = datetime.now().strftime("%H:%M")
        full_msg = f"{commit_msg} ({timestamp})"
        
        # Commit
        stdout, stderr, code = run_command(f'git commit -m "{full_msg}"')
        
        if code == 0:
            print(f"✅ Auto-committed: {full_msg}")
            
            # Try to push if we have a remote
            stdout, _, push_code = run_command("git push 2>/dev/null")
            if push_code == 0:
                print("📤 Auto-pushed to remote")
        else:
            print(f"❌ Commit failed: {stderr}")
            
    except Exception as e:
        print(f"❌ Smart commit error: {e}")
        sys.exit(0)  # Don't block Claude

if __name__ == "__main__":
    main()