
import hashlib
from pathlib import Path
from typing import Dict, List, Tuple
from collections import defaultdict

from .logger import logger
from .utils import is_hidden, is_system_file


def calculate_file_hash(file_path: Path, chunk_size: int = 8192) -> str:
    """Calculate SHA256 hash of file."""
    sha256 = hashlib.sha256()
    try:
        with open(file_path, "rb") as f:
            while chunk := f.read(chunk_size):
                sha256.update(chunk)
        return sha256.hexdigest()
    except (OSError, IOError) as e:
        logger.error(f"Error reading file {file_path}: {e}")
        return ""


def find_duplicates(directory: Path, recursive: bool = True, include_hidden: bool = False) -> Dict[str, List[Path]]:
    """
    Find duplicate files in directory.

    Returns dict with hash as key and list of file paths as value.
    Only includes hashes with multiple files.
    """
    hashes: Dict[str, List[Path]] = defaultdict(list)

    if recursive:
        files = directory.rglob("*")
    else:
        files = directory.iterdir()

    for file_path in files:
        if not file_path.is_file():
            continue
        if not include_hidden and (is_hidden(file_path) or is_system_file(file_path)):
            continue

        file_hash = calculate_file_hash(file_path)
        if file_hash:
            hashes[file_hash].append(file_path)

    # Filter to only duplicates
    duplicates = {h: paths for h, paths in hashes.items() if len(paths) > 1}
    return duplicates


def print_duplicates(duplicates: Dict[str, List[Path]]) -> None:
    """Print duplicate files."""
    if not duplicates:
        print("No duplicates found.")
        return

    total_duplicates = sum(len(paths) - 1 for paths in duplicates.values())
    print(f"Found {len(duplicates)} duplicate groups with {total_duplicates} duplicate files:")

    for i, (hash_val, paths) in enumerate(duplicates.items(), 1):
        print(f"\nGroup {i} (Hash: {hash_val[:16]}...):")
        for path in paths:
            print(f"  {path}")


def get_duplicate_stats(duplicates: Dict[str, List[Path]]) -> Tuple[int, int, int]:
    """Get statistics: groups, total duplicates, total files."""
    groups = len(duplicates)
    total_duplicates = sum(len(paths) - 1 for paths in duplicates.values())
    total_files = sum(len(paths) for paths in duplicates.values())
    return groups, total_duplicates, total_files