"""
Full inventory of dumps/ directory.
Produces:
  - data/inventory.csv  (every file in every dump)
  - data/hosts.csv      (parsed system_info.txt per dump)
"""

import csv
import os
import re
import sys
import time
from pathlib import Path

ROOT_DIR = Path(__file__).resolve().parents[2]
LEGACY_ROOT = ROOT_DIR / "findings" / "legacy_dump_assessment"
DUMPS_DIR = LEGACY_ROOT / "dumps"
DATA_DIR = ROOT_DIR / "findings" / "data"

INVENTORY_CSV = DATA_DIR / "legacy_dump_inventory.csv"
HOSTS_CSV = DATA_DIR / "legacy_dump_hosts.csv"

INVENTORY_FIELDS = [
    "dump_id",
    "relative_path",
    "category",
    "extension",
    "size_bytes",
    "filename",
]

HOSTS_FIELDS = [
    "dump_id",
    "scan_date",
    "computer_name",
    "username",
    "os",
    "architecture",
]

NUM_PREFIX_RE = re.compile(r"^\d{3}_")


def parse_dump_id(folder_name: str) -> int:
    """Extract numeric id from folder name: 'dump' -> 0, 'dump (42)' -> 42."""
    if folder_name == "dump":
        return 0
    m = re.search(r"\((\d+)\)", folder_name)
    return int(m.group(1)) if m else -1


def classify_category(rel_path: str) -> str:
    """Determine category from the relative path inside a dump."""
    parts = Path(rel_path).parts
    if len(parts) == 1:
        return "root"
    top = parts[0].lower()
    if top == "files" and len(parts) >= 2:
        return f"files/{parts[1].lower()}"
    return top


def strip_numeric_prefix(filename: str) -> str:
    """Remove leading NNN_ prefix from filenames like '001_id_rsa'."""
    return NUM_PREFIX_RE.sub("", filename)


def parse_system_info(path: Path) -> dict:
    """Parse system_info.txt into a dict."""
    info = {
        "scan_date": "",
        "computer_name": "",
        "username": "",
        "os": "",
        "architecture": "",
    }
    try:
        text = path.read_text(encoding="utf-8", errors="replace")
        for line in text.splitlines():
            line = line.strip()
            if ":" in line:
                key, _, value = line.partition(":")
                key = key.strip().lower().replace(" ", "_")
                value = value.strip()
                if key == "scan_date":
                    info["scan_date"] = value
                elif key == "computer_name":
                    info["computer_name"] = value
                elif key == "username":
                    info["username"] = value
                elif key == "os":
                    info["os"] = value
                elif key == "architecture":
                    info["architecture"] = value
    except Exception as e:
        print(f"  Warning: could not parse {path}: {e}", file=sys.stderr)
    return info


def run():
    DATA_DIR.mkdir(parents=True, exist_ok=True)

    dump_folders = sorted(
        [d for d in DUMPS_DIR.iterdir() if d.is_dir()],
        key=lambda d: parse_dump_id(d.name),
    )

    print(f"Found {len(dump_folders)} dump folders")
    t0 = time.time()
    total_files = 0

    with (
        open(INVENTORY_CSV, "w", newline="", encoding="utf-8") as inv_f,
        open(HOSTS_CSV, "w", newline="", encoding="utf-8") as hosts_f,
    ):
        inv_writer = csv.DictWriter(inv_f, fieldnames=INVENTORY_FIELDS)
        inv_writer.writeheader()

        hosts_writer = csv.DictWriter(hosts_f, fieldnames=HOSTS_FIELDS)
        hosts_writer.writeheader()

        for i, dump_dir in enumerate(dump_folders):
            dump_id = parse_dump_id(dump_dir.name)

            sys_info_path = dump_dir / "system_info.txt"
            if sys_info_path.exists():
                info = parse_system_info(sys_info_path)
                hosts_writer.writerow({"dump_id": dump_id, **info})

            dump_file_count = 0
            for root, _dirs, files in os.walk(dump_dir):
                for fname in files:
                    full_path = Path(root) / fname
                    rel_path = full_path.relative_to(dump_dir).as_posix()
                    ext = full_path.suffix.lower()
                    try:
                        size = full_path.stat().st_size
                    except OSError:
                        size = -1

                    inv_writer.writerow(
                        {
                            "dump_id": dump_id,
                            "relative_path": rel_path,
                            "category": classify_category(rel_path),
                            "extension": ext,
                            "size_bytes": size,
                            "filename": strip_numeric_prefix(fname),
                        }
                    )
                    dump_file_count += 1

            total_files += dump_file_count
            if (i + 1) % 50 == 0 or i == len(dump_folders) - 1:
                elapsed = time.time() - t0
                print(
                    f"  [{i+1}/{len(dump_folders)}] "
                    f"dump_id={dump_id} | "
                    f"{dump_file_count} files | "
                    f"total={total_files} | "
                    f"{elapsed:.1f}s"
                )

    elapsed = time.time() - t0
    print(f"\nDone in {elapsed:.1f}s")
    print(f"  {INVENTORY_CSV}  ({total_files} rows)")
    print(f"  {HOSTS_CSV}  ({len(dump_folders)} rows)")


if __name__ == "__main__":
    run()
