#!/usr/bin/env python3
"""Inventaria una cartella locale e segnala duplicati esatti senza modificarla."""

from __future__ import annotations

import argparse
import csv
import hashlib
from collections import defaultdict
from pathlib import Path


def sha256_file(path: Path, chunk_size: int = 1024 * 1024) -> str:
    digest = hashlib.sha256()
    with path.open("rb") as handle:
        for chunk in iter(lambda: handle.read(chunk_size), b""):
            digest.update(chunk)
    return digest.hexdigest()


def inventory(root: Path) -> list[dict[str, str | int]]:
    rows: list[dict[str, str | int]] = []
    for path in sorted(item for item in root.rglob("*") if item.is_file()):
        stat = path.stat()
        rows.append({
            "relative_path": path.relative_to(root).as_posix(),
            "extension": path.suffix.lower() or "[senza-estensione]",
            "bytes": stat.st_size,
            "sha256": sha256_file(path),
        })
    return rows


def duplicate_groups(rows: list[dict[str, str | int]]) -> list[list[str]]:
    groups: dict[tuple[int, str], list[str]] = defaultdict(list)
    for row in rows:
        groups[(int(row["bytes"]), str(row["sha256"]))].append(str(row["relative_path"]))
    return [sorted(paths) for paths in groups.values() if len(paths) > 1]


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("source", type=Path, help="Cartella locale da leggere")
    parser.add_argument("--output-dir", type=Path, required=True, help="Cartella per i report")
    args = parser.parse_args()
    if not args.source.is_dir():
        parser.error("La sorgente deve essere una cartella esistente.")
    root = args.source.resolve()
    rows = inventory(root)
    duplicates = duplicate_groups(rows)
    args.output_dir.mkdir(parents=True, exist_ok=True)
    with (args.output_dir / "file-inventory.csv").open("w", newline="", encoding="utf-8") as handle:
        writer = csv.DictWriter(handle, fieldnames=["relative_path", "extension", "bytes", "sha256"])
        writer.writeheader()
        writer.writerows(rows)
    with (args.output_dir / "duplicate-groups.md").open("w", encoding="utf-8") as handle:
        handle.write("# Possibili duplicati esatti\n\n")
        if not duplicates:
            handle.write("Nessun gruppo trovato.\n")
        for index, paths in enumerate(duplicates, start=1):
            handle.write(f"## Gruppo {index}\n\n")
            handle.writelines(f"- `{path}`\n" for path in paths)
            handle.write("\nDecisione: DA VALUTARE — nessun file è stato modificato.\n\n")
    print(f"Inventariati {len(rows)} file; gruppi duplicati esatti: {len(duplicates)}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
