#!/usr/bin/env python3
"""
BradenWorks Disk Usage Scanner
================================
WHAT IT DOES:
    Scans a folder and shows you the biggest space hogs - the largest
    files and which subfolders use the most disk. READ-ONLY: it never
    deletes, moves, or changes anything. Pure reporting.

HOW TO RUN:
    python disk-usage.py                 (scans your home folder)
    python disk-usage.py C:\\Users\\You  (scans a specific folder)
    python disk-usage.py --top 20       (show top 20 instead of 10)

SAFETY:
    Standard library only (no installs needed). Makes zero network
    calls, collects zero telemetry, writes nothing. Safe on any OS
    with Python 3.6+.

TIP: run it, find what's eating your disk, then delete what you
don't need yourself - or use cleanup.ps1 for the automatic temp
file pass.
"""

import os
import sys
import argparse


def fmt_size(num_bytes):
    """Human-readable file size."""
    for unit in ("B", "KB", "MB", "GB", "TB"):
        if num_bytes < 1024 or unit == "TB":
            return f"{num_bytes:,.1f} {unit}"
        num_bytes /= 1024.0


def scan(root):
    """Walk root, return (top_files, folder_sizes). Skips what it can't read."""
    top_files = []          # (size, path)
    folder_sizes = {}       # folder -> total bytes (top-level only)
    scanned = 0
    errors = 0

    try:
        top_level = {
            os.path.join(root, d) for d in os.listdir(root)
            if os.path.isdir(os.path.join(root, d))
        }
    except OSError:
        print(f"Cannot read folder: {root}")
        sys.exit(1)

    for dirpath, dirnames, filenames in os.walk(root, onerror=lambda e: None,
                                                followlinks=False):
        for name in filenames:
            fp = os.path.join(dirpath, name)
            try:
                size = os.path.getsize(fp)
            except OSError:
                errors += 1
                continue
            scanned += 1
            top_files.append((size, fp))
            # attribute to the top-level folder it lives under
            for top in top_level:
                if fp.startswith(top + os.sep):
                    folder_sizes[top] = folder_sizes.get(top, 0) + size
                    break

    top_files.sort(reverse=True)
    return top_files, folder_sizes, scanned, errors


def main():
    ap = argparse.ArgumentParser(description="Find what's eating your disk (read-only).")
    ap.add_argument("folder", nargs="?", default=os.path.expanduser("~"),
                    help="Folder to scan (default: your home folder)")
    ap.add_argument("--top", type=int, default=10, help="How many entries to show")
    args = ap.parse_args()

    root = os.path.abspath(args.folder)
    print(f"\nScanning: {root}\n")

    top_files, folder_sizes, scanned, errors = scan(root)
    total = sum(s for s, _ in top_files)

    print(f"Scanned {scanned:,} files ({fmt_size(total)} total)"
          + (f", skipped {errors} unreadable" if errors else ""))
    print(f"\n--- Biggest folders ---")
    for folder, size in sorted(folder_sizes.items(), reverse=True)[:args.top]:
        pct = (size / total * 100) if total else 0
        print(f"  {fmt_size(size):>12}  ({pct:4.1f}%)  {os.path.basename(folder)}")

    print(f"\n--- Biggest individual files ---")
    for size, path in top_files[:args.top]:
        print(f"  {fmt_size(size):>12}  {path}")

    print("\nDone. Nothing was changed - this tool only reports.\n")


if __name__ == "__main__":
    main()
