#!/usr/bin/env python3
"""Listet alle Dateien und Ordner eines Verzeichnisses auf.
 
Beispiele:
    python lister.py                # aktuelles Verzeichnis
    python lister.py /pfad/zum/ordner
    python lister.py -a             # inkl. versteckter Dateien
    python lister.py -r             # rekursiv (Baumansicht)
"""
 
import argparse
import sys
from pathlib import Path
 
 
def format_size(num_bytes: int) -> str:
    """Wandelt Bytes in eine lesbare Groesse um."""
    size = float(num_bytes)
    for unit in ("B", "KB", "MB", "GB", "TB"):
        if size < 1024 or unit == "TB":
            return f"{size:.0f} {unit}" if unit == "B" else f"{size:.1f} {unit}"
        size /= 1024
    return f"{size:.1f} TB"
 
 
def get_entries(directory: Path, show_hidden: bool):
    """Liefert die Eintraege eines Verzeichnisses: Ordner zuerst, dann alphabetisch."""
    try:
        entries = list(directory.iterdir())
    except PermissionError:
        return []
    if not show_hidden:
        entries = [e for e in entries if not e.name.startswith(".")]
    return sorted(entries, key=lambda e: (not e.is_dir(), e.name.lower()))
 
 
def print_flat(directory: Path, show_hidden: bool) -> tuple[int, int]:
    """Einfache Liste des Verzeichnisses."""
    dirs = files = 0
    for entry in get_entries(directory, show_hidden):
        if entry.is_dir():
            print(f"  [DIR]   {entry.name}/")
            dirs += 1
        else:
            try:
                size = format_size(entry.stat().st_size)
            except OSError:
                size = "?"
            print(f"  [FILE]  {entry.name:<40} {size:>10}")
            files += 1
    return dirs, files
 
 
def print_tree(directory: Path, show_hidden: bool, prefix: str = "") -> tuple[int, int]:
    """Rekursive Baumansicht."""
    dirs = files = 0
    entries = get_entries(directory, show_hidden)
    for index, entry in enumerate(entries):
        is_last = index == len(entries) - 1
        connector = "`-- " if is_last else "|-- "
        if entry.is_dir():
            print(f"{prefix}{connector}{entry.name}/")
            dirs += 1
            sub_prefix = prefix + ("    " if is_last else "|   ")
            sub_dirs, sub_files = print_tree(entry, show_hidden, sub_prefix)
            dirs += sub_dirs
            files += sub_files
        else:
            print(f"{prefix}{connector}{entry.name}")
            files += 1
    return dirs, files
 
 
def main() -> int:
    parser = argparse.ArgumentParser(
        description="Listet alle Dateien und Ordner in einem Verzeichnis auf."
    )
    parser.add_argument("pfad", nargs="?", default=".", help="Zielverzeichnis (Standard: .)")
    parser.add_argument("-a", "--alle", action="store_true", help="versteckte Eintraege anzeigen")
    parser.add_argument("-r", "--rekursiv", action="store_true", help="Unterordner mit anzeigen")
    args = parser.parse_args()
 
    directory = Path(args.pfad).expanduser().resolve()
    if not directory.exists():
        print(f"Fehler: '{directory}' existiert nicht.", file=sys.stderr)
        return 1
    if not directory.is_dir():
        print(f"Fehler: '{directory}' ist kein Verzeichnis.", file=sys.stderr)
        return 1
 
    print(f"\n{directory}\n")
    if args.rekursiv:
        dirs, files = print_tree(directory, args.alle)
    else:
        dirs, files = print_flat(directory, args.alle)
 
    print(f"\n{dirs} Ordner, {files} Dateien\n")
    return 0
 
 
if __name__ == "__main__":
    raise SystemExit(main())