# retoor <retoor@molodetz.nl>

import hashlib
import json
import sys
import tarfile
from pathlib import Path

CHUNK_SIZE = 1024 * 1024


def _reset(info: tarfile.TarInfo) -> tarfile.TarInfo:
    info.uid = 0
    info.gid = 0
    info.uname = ""
    info.gname = ""
    return info


def _add_file(archive: tarfile.TarFile, full: Path, arcname: str) -> int:
    size = full.stat().st_size
    info = _reset(archive.gettarinfo(str(full), arcname=arcname))
    with full.open("rb") as handle:
        archive.addfile(info, handle)
    return size


def _build(spec: dict, output_path: str) -> dict:
    bytes_in = 0
    file_count = 0
    dir_count = 0
    with tarfile.open(output_path, "w:gz") as archive:
        for source in spec.get("sources", []):
            root = source["root"]
            base = Path(source["path"])
            if not base.exists():
                continue
            if base.is_file():
                bytes_in += _add_file(archive, base, f"{root}/{base.name}")
                file_count += 1
                continue
            for entry in sorted(base.rglob("*"), key=lambda p: str(p)):
                arcname = f"{root}/{entry.relative_to(base)}"
                if entry.is_symlink():
                    continue
                if entry.is_dir():
                    info = _reset(archive.gettarinfo(str(entry), arcname=arcname))
                    archive.addfile(info)
                    dir_count += 1
                elif entry.is_file():
                    try:
                        bytes_in += _add_file(archive, entry, arcname)
                        file_count += 1
                    except OSError:
                        continue

    digest = hashlib.sha256()
    with open(output_path, "rb") as handle:
        for chunk in iter(lambda: handle.read(CHUNK_SIZE), b""):
            digest.update(chunk)

    return {
        "bytes_in": bytes_in,
        "bytes_out": Path(output_path).stat().st_size,
        "file_count": file_count,
        "dir_count": dir_count,
        "sha256": digest.hexdigest(),
    }


def main(argv: list) -> int:
    if len(argv) != 3:
        sys.stderr.write("usage: backup_worker <spec_json> <output_tar_gz>\n")
        return 2
    spec_path, output_path = argv[1], argv[2]
    spec = json.loads(Path(spec_path).read_text())
    stats = _build(spec, output_path)
    sys.stdout.write(json.dumps(stats))
    return 0


if __name__ == "__main__":
    raise SystemExit(main(sys.argv))
