import os
import glob


def compute_directory_size(path):
    """Recursively calculates the total file size of a directory."""
    total_size = 0
    for dirpath, dirnames, filenames in os.walk(path):
        for f in filenames:
            fp = os.path.join(dirpath, f)
            if os.path.exists(fp):
                total_size += os.path.getsize(fp)
    return total_size


def get_chrome_cache_targets(profile_path=None):
    """Returns a dictionary of cache target directories for Chrome.

    Args:
        profile_path: Path to a specific Chrome profile. If None, uses the default profile.

    Returns:
        Dictionary mapping cache category names to their paths.
    """
    chrome_base = os.path.expanduser("~/Library/Application Support/Google/Chrome")

    if profile_path is None:
        profile_path = os.path.join(chrome_base, "Default")

    cache_targets = {
        "Cache": os.path.join(profile_path, "Cache"),
        "Code Cache": os.path.join(profile_path, "Code Cache"),
        "GPUCache": os.path.join(profile_path, "GPUCache"),
        "Service Worker Cache": os.path.join(
            profile_path, "Service Worker/CacheStorage"
        ),
        "Service Worker Scripts": os.path.join(
            profile_path, "Service Worker/ScriptCache"
        ),
        "Media Cache": os.path.join(profile_path, "Media Cache"),
        "File System": os.path.join(profile_path, "File System"),
        "IndexedDB": os.path.join(profile_path, "IndexedDB"),
        "Local Storage": os.path.join(profile_path, "Local Storage"),
        "Session Storage": os.path.join(profile_path, "Session Storage"),
        "Web Storage": os.path.join(profile_path, "WebStorage"),
    }

    # Add Chrome-wide cache directories
    cache_targets.update(
        {
            "Shader Cache": os.path.join(chrome_base, "ShaderCache"),
            "GrShader Cache": os.path.join(chrome_base, "GrShaderCache"),
            "Component CRX Cache": os.path.join(chrome_base, "component_crx_cache"),
            "Screen AI": os.path.join(chrome_base, "screen_ai"),
            "Optimization Guide": os.path.join(
                chrome_base, "optimization_guide_model_store"
            ),
            "Crash Reports": os.path.join(chrome_base, "CrashReports"),
            "Crashpad": os.path.join(chrome_base, "Crashpad/completed"),
        }
    )

    return cache_targets


def get_chrome_profiles():
    """Discovers all Chrome profiles.

    Returns:
        List of tuples containing (profile_name, profile_path).
    """
    chrome_base = os.path.expanduser("~/Library/Application Support/Google/Chrome")
    profiles = []

    if not os.path.exists(chrome_base):
        return profiles

    # Always include Default profile
    default_path = os.path.join(chrome_base, "Default")
    if os.path.exists(default_path):
        profiles.append(("Default", default_path))

    # Find all Profile directories
    for item in os.listdir(chrome_base):
        if item.startswith("Profile ") and os.path.isdir(
            os.path.join(chrome_base, item)
        ):
            profiles.append((item, os.path.join(chrome_base, item)))

    return profiles


def categorize_chrome_cache(profile_path=None):
    """Categorizes Chrome cache data into safe and unsafe to delete.

    Args:
        profile_path: Path to a specific Chrome profile. If None, scans all profiles.

    Returns:
        Dictionary with categorized cache data.
    """
    categories = {
        "safe": {
            "Cache Files": [],
            "Service Worker": [],
            "Temporary Files": [],
            "Developer Cache": [],
            "Media Cache": [],
        },
        "unsafe": {
            "User Data": [],
            "Extensions": [],
            "Settings": [],
        },
    }

    chrome_base = os.path.expanduser("~/Library/Application Support/Google/Chrome")

    # Safe patterns - can be deleted without losing user data
    safe_patterns = {
        "Cache Files": [
            "*/Cache/*",
            "*/Code Cache/*",
            "*/GPUCache/*",
            "ShaderCache/*",
            "GrShaderCache/*",
            "component_crx_cache/*",
        ],
        "Service Worker": [
            "*/Service Worker/CacheStorage/*",
            "*/Service Worker/ScriptCache/*",
        ],
        "Temporary Files": ["*/Temp/*", "*/.com.google.Chrome.*", "screen_ai/*"],
        "Developer Cache": ["*/File System/*", "*/IndexedDB/*"],
        "Media Cache": ["*/Media Cache/*", "optimization_guide_model_store/*"],
    }

    # Unsafe patterns - contains user data, bookmarks, passwords, etc.
    unsafe_patterns = {
        "User Data": ["*/History*", "*/Bookmarks*", "*/Favicons*", "*/Login Data*"],
        "Extensions": [
            "*/Extensions/*",
            "*/Extension State/*",
            "*/Local Extension Settings/*",
        ],
        "Settings": ["*/Preferences", "*/Secure Preferences", "*/Local State"],
    }

    # Scan safe patterns
    for category, patterns in safe_patterns.items():
        for pattern in patterns:
            full_pattern = os.path.join(chrome_base, pattern)
            for path in glob.glob(full_pattern):
                try:
                    if os.path.isfile(path):
                        size = os.path.getsize(path)
                        categories["safe"][category].append((path, size, "file"))
                    elif os.path.isdir(path):
                        size = compute_directory_size(path)
                        if size > 0:
                            categories["safe"][category].append((path, size, "dir"))
                except (OSError, PermissionError):
                    continue

    # Scan unsafe patterns (for reporting only)
    for category, patterns in unsafe_patterns.items():
        for pattern in patterns:
            full_pattern = os.path.join(chrome_base, pattern)
            for path in glob.glob(full_pattern):
                try:
                    if os.path.isfile(path):
                        size = os.path.getsize(path)
                        categories["unsafe"][category].append((path, size, "file"))
                    elif os.path.isdir(path):
                        size = compute_directory_size(path)
                        if size > 0:
                            categories["unsafe"][category].append((path, size, "dir"))
                except (OSError, PermissionError):
                    continue

    return categories


def generate_chrome_cache_report(include_profiles=True):
    """Generates a detailed cache report for Chrome.

    Args:
        include_profiles: Whether to scan all profiles or just the default.

    Returns:
        Dictionary containing the cache report.
    """
    chrome_base = os.path.expanduser("~/Library/Application Support/Google/Chrome")

    if not os.path.exists(chrome_base):
        return {
            "installed": False,
            "profiles": [],
            "total_size": 0,
            "safe_size": 0,
            "categories": {},
        }

    profiles = (
        get_chrome_profiles()
        if include_profiles
        else [("Default", os.path.join(chrome_base, "Default"))]
    )
    profile_reports = []
    total_size = 0
    safe_size = 0

    # Get categorized data
    categories = categorize_chrome_cache()

    # Calculate sizes
    for category_type, category_data in categories.items():
        for category_name, items in category_data.items():
            for path, size, item_type in items:
                total_size += size
                if category_type == "safe":
                    safe_size += size

    # Generate per-profile reports if requested
    if include_profiles:
        for profile_name, profile_path in profiles:
            profile_cache_targets = get_chrome_cache_targets(profile_path)
            profile_size = 0
            cache_dirs = {}

            for cache_name, cache_path in profile_cache_targets.items():
                if cache_name in [
                    "Shader Cache",
                    "GrShader Cache",
                    "Component CRX Cache",
                    "Screen AI",
                    "Optimization Guide",
                    "Crash Reports",
                    "Crashpad",
                ]:
                    continue  # Skip Chrome-wide caches for individual profiles

                exists = os.path.exists(cache_path)
                size = compute_directory_size(cache_path) if exists else 0
                profile_size += size
                cache_dirs[cache_name] = {
                    "exists": exists,
                    "size": size,
                    "path": cache_path,
                }

            profile_reports.append(
                {
                    "name": profile_name,
                    "path": profile_path,
                    "cache_dirs": cache_dirs,
                    "total_size": profile_size,
                }
            )

    return {
        "installed": True,
        "chrome_base": chrome_base,
        "profiles": profile_reports,
        "total_size": total_size,
        "safe_size": safe_size,
        "unsafe_size": total_size - safe_size,
        "categories": categories,
    }


def scan_chrome_cache(include_profiles=True):
    """
    Scans Chrome cache to generate a report of cleanable files.

    This is a cleaner interface for scanning Chrome cache that matches
    the Unity project scanner pattern.

    Args:
        include_profiles: Boolean indicating whether to scan all profiles.

    Returns:
        A dictionary containing Chrome's cache report.
    """
    return generate_chrome_cache_report(include_profiles=include_profiles)
