"""Git utilities for analyzing repositories."""

import os
from pathlib import Path
from typing import Optional, Dict, Any, List
from datetime import datetime
from git import Repo, InvalidGitRepositoryError, GitCommandError


def find_git_repo(path: str = ".") -> Optional[Repo]:
    """Find and return a git repository."""
    try:
        repo = Repo(path, search_parent_directories=True)
        return repo
    except InvalidGitRepositoryError:
        return None


def get_repo_path(repo: Optional[Repo] = None) -> str:
    """Get the absolute path of a git repository."""
    if repo is None:
        repo = find_git_repo()
    
    if repo:
        return str(Path(repo.working_dir).resolve())
    return str(Path.cwd().resolve())


def is_clean_commit_message(message: str) -> bool:
    """Determine if a commit message is 'clean' (descriptive)."""
    message_lower = message.strip().lower()
    
    # Too short
    if len(message_lower) < 10:
        return False
    
    # Common WIP indicators (stricter matching)
    wip_indicators = [
        "wip", "fixup", "tmp", "temp", "asdf", "qwer",
        "fuck", "shit", "damn", "wtf", "lol",
    ]
    
    # Check for whole word matches or at word boundaries
    for indicator in wip_indicators:
        if indicator == message_lower or f" {indicator} " in f" {message_lower} ":
            return False
    
    # Bad patterns
    bad_patterns = ["fixed stuff", "fix stuff", "did stuff", "stuff", "things"]
    if any(pattern == message_lower or f" {pattern} " in f" {message_lower} " for pattern in bad_patterns):
        return False
    
    # Single word commits (except meaningful ones)
    meaningful_singles = ["initial", "refactor", "merge", "rebase", "release"]
    if " " not in message_lower and message_lower not in meaningful_singles:
        return False
    
    return True


def get_last_commit(repo: Optional[Repo] = None) -> Optional[Dict[str, Any]]:
    """Get information about the last commit."""
    if repo is None:
        repo = find_git_repo()
    
    if not repo or not repo.head.is_valid():
        return None
    
    try:
        commit = repo.head.commit
        
        # Get diff stats
        stats = commit.stats.total
        
        return {
            "hash": commit.hexsha,
            "short_hash": commit.hexsha[:7],
            "message": commit.message.strip(),
            "author": commit.author.name,
            "email": commit.author.email,
            "timestamp": datetime.fromtimestamp(commit.committed_date).isoformat(),
            "files_changed": stats.get("files", 0),
            "lines_added": stats.get("insertions", 0),
            "lines_deleted": stats.get("deletions", 0),
            "is_clean": is_clean_commit_message(commit.message),
            "repo_path": get_repo_path(repo),
        }
    except Exception as e:
        print(f"Error getting last commit: {e}")
        return None


def get_recent_commits(repo: Optional[Repo] = None, count: int = 10) -> List[Dict[str, Any]]:
    """Get recent commits."""
    if repo is None:
        repo = find_git_repo()
    
    if not repo or not repo.head.is_valid():
        return []
    
    commits = []
    try:
        for commit in repo.iter_commits(max_count=count):
            stats = commit.stats.total
            commits.append({
                "hash": commit.hexsha,
                "short_hash": commit.hexsha[:7],
                "message": commit.message.strip(),
                "author": commit.author.name,
                "email": commit.author.email,
                "timestamp": datetime.fromtimestamp(commit.committed_date).isoformat(),
                "files_changed": stats.get("files", 0),
                "lines_added": stats.get("insertions", 0),
                "lines_deleted": stats.get("deletions", 0),
                "is_clean": is_clean_commit_message(commit.message),
                "repo_path": get_repo_path(repo),
            })
    except Exception as e:
        print(f"Error getting recent commits: {e}")
    
    return commits


def get_diff_stats(repo: Optional[Repo] = None) -> Dict[str, Any]:
    """Get current diff statistics (unstaged changes)."""
    if repo is None:
        repo = find_git_repo()
    
    if not repo:
        return {"files_changed": 0, "lines_added": 0, "lines_deleted": 0}
    
    try:
        # Get diff between HEAD and working directory
        diff_index = repo.head.commit.diff(None, create_patch=True)
        
        files_changed = len(diff_index)
        lines_added = 0
        lines_deleted = 0
        
        for diff_item in diff_index:
            if diff_item.diff:
                diff_text = diff_item.diff.decode("utf-8", errors="ignore")
                for line in diff_text.split("\n"):
                    if line.startswith("+") and not line.startswith("+++"):
                        lines_added += 1
                    elif line.startswith("-") and not line.startswith("---"):
                        lines_deleted += 1
        
        return {
            "files_changed": files_changed,
            "lines_added": lines_added,
            "lines_deleted": lines_deleted,
        }
    except Exception as e:
        print(f"Error getting diff stats: {e}")
        return {"files_changed": 0, "lines_added": 0, "lines_deleted": 0}


def analyze_commit_patterns(repo: Optional[Repo] = None, days: int = 30) -> Dict[str, Any]:
    """Analyze commit patterns over time."""
    if repo is None:
        repo = find_git_repo()
    
    if not repo or not repo.head.is_valid():
        return {
            "total_commits": 0,
            "clean_commits": 0,
            "avg_files_per_commit": 0,
            "avg_lines_per_commit": 0,
        }
    
    try:
        commits = get_recent_commits(repo, count=100)
        
        if not commits:
            return {
                "total_commits": 0,
                "clean_commits": 0,
                "avg_files_per_commit": 0,
                "avg_lines_per_commit": 0,
            }
        
        clean_count = sum(1 for c in commits if c["is_clean"])
        total_files = sum(c["files_changed"] for c in commits)
        total_lines = sum(c["lines_added"] + c["lines_deleted"] for c in commits)
        
        return {
            "total_commits": len(commits),
            "clean_commits": clean_count,
            "clean_ratio": clean_count / len(commits) if commits else 0,
            "avg_files_per_commit": total_files / len(commits) if commits else 0,
            "avg_lines_per_commit": total_lines / len(commits) if commits else 0,
        }
    except Exception as e:
        print(f"Error analyzing commit patterns: {e}")
        return {
            "total_commits": 0,
            "clean_commits": 0,
            "avg_files_per_commit": 0,
            "avg_lines_per_commit": 0,
        }
